From 5776aad0f1b35b6fdce1bca9407bcda4ed73e17f Mon Sep 17 00:00:00 2001 From: Robin Lindner Date: Thu, 23 Jun 2022 09:12:36 +0200 Subject: [PATCH] Sfh fix tests (#8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use the signature types when building ABI info (#70635) * Use signature types when building the ABI info This will allow us to let "mismatched" struct types as call arguments, which in turn is expected to simplify and de-pessimize much of the code working around the need to keep precise handles on struct nodes. Credit to @jakobbotsch for being able to make this change. * Work around the "InferOpSizeAlign" problem Handling it generally requires solving a larger problem of "eeGetArgSizeAlignment" not working well on ARM. (See also the use of "eeGetArgSizeAlignment" in "lvaInitUserArgs") * [wasm] Build WasmAppHost with UseAppHost=false (#70606) * [wasm] Build WasmAppHost with UseAppHost=false - WasmAppHost is included in the WebAssembly.Sdk pack, and doesn't have a platform specific package. - Since, this is being built for x64, the build defaults to using the app host, which means that we get a single binary file that can be run directly. - But this also means that the binary included in the WebAssembly.Sdk platform-agnostic package will target the platform where it was built. - Instead, build with UseAppHost=false, and update the wasm host to use the managed assembly instead. And update the RunCommand to use `dotnet exec WasmAppHost.dll`. * fix * JIT: Optimize expansion of indir cell addresses for CFG (#70491) On ARM64 it is expensive to materialize the address of an indirection cell since that requires multiple instructions. This is particular a problem when CFG is enabled where validation + call uses the indir cell twice. This changes the CFG logic to create a local in this case. We also were forcing the indir cell argument node into the register. This is not ideal for this particular case, so remove this logic and let LSRA deal with it. ARM still needs this logic. Fix #65076 * Handle mis-sized structs in XARCH `PUTARG_STK` codegen (#68611) * Handle "mis-sized" structs in XARCH PUTARG_STK codegen Previously, for structs which were not a multiple of TARGET_POINTER_SIZE in size: 1) On x86, we copied them to a local in morph. This was a small CQ issue. 2) On Unix x64, we didn't handle them at all and could read out of bounds in "genStructPutArgUnroll". This change fixes both issues by properly detecting cases where we need to be careful and updating codegen to use correct load sizes. * Add a test * Improve distribution of CoseHeaderLabel hash codes (#70695) * Implement digest one shots for browser implementation * [wasm] Don't use a fixed listening port for the proxy (#70681) Fixes https://github.com/dotnet/runtime/issues/70670 . * Fix SOS tests on 7.0 (#70677) The wcscpy_s in ClrDataAccess::GetRegisterName was failing with an invalid parameter exception because the prefixLen and regLen didn't include the terminating null wchar. * [wasm] Enable some previously failing WBT/AOT tests on windows (#70595) * [wasm] Enable some previously failing WBT/AOT tests on windows Fixes https://github.com/dotnet/runtime/issues/61725 . * [wasm] WBT: Fix a failing satellite assembly test The test fails because it is trying to find the string `got: こんにちは` in the app output, but it sees `?????`. This is due to xharness not setting the console output to UTF8, and then the tests not doing the same. Instead of that, we can move the check to be in the app itself, thus removing the need for any of this. Fixes https://github.com/dotnet/runtime/issues/58709 . * List other architectures and DOTNET_ROOT environment variables in dotnet --info (#70403) * [mono] Remove dead code. (#70671) A variable initialized to false and never modified means we can remove the variable and any code that depends on that variable not being false. This is a consequence of 15ab9f985ed45feaa619df70d288fbd0acd5c45f, where code that assigned the variable was removed. * Avoid throwing Win32Exception from HTTP authentication (#70474) * Avoid throwing Win32Exception from HTTP authentication When server sends malformed NTLM challenge the NT authentication processing would throw an unexpected Win32Exception from HttpClientHandler.Send[Async] calls. This aligns the behavior to WinHTTP handler where the Unauthorized reply with challenge token is returned back to the client. Similarly, failure to validate the last MIC token in Negotiate scheme could result in Win32Exception. Handle it by throwing HttpRequestException instead. * Make the unit test more resilient * Add trace to Negotiate authentication * Dispose connection instead of draining the response * Remove outdated ActiveIssue * Fix usage of GSS_KRB5_CRED_NO_CI_FLAGS_X (#70447) * Fix build detection of GSS_KRB5_CRED_NO_CI_FLAGS_X * Don't use GSS_KRB5_CRED_NO_CI_FLAGS_X on NTLM * Handle GSS_S_UNAVAILABLE error from gss_set_cred_option (NTLM wrapped in Negotiate) * Make the GSSAPI shim work with krb5 1.13 * Preserve the gss_acquire_cred minor status * Use IndexOf in WebUtility (#70700) The IndexOfHtmlDecodingChars method was iterating character by character looking for either a `&` or a surrogate, but then the slow path if one of those is found doesn't special-case surrogates. So, we can just collapse this to a vectorized `IndexOf('&')`, which makes the fast path of detecting whether there's anything to decode much faster if there's any meaningful amount of input prior to a `&`. (I experimented with also using `IndexOf('&')` in the main routine, but it made cases with lots of entities slower, and so I'm not including that here.) * Hoist the invariants out of multi-level nested loops (#68061) * first working version * Skip check of VN hoisting * Account for duplicate blocks * clean up * wip * isCommaTree && hasExcep * revert lsra changes * Update hoisting condition - Only update if node to be hoisted has side-effects and the sibling that is before that throws exception * Change to BasicBlockList * organize preheaders * update hoistedInCurLoop and hoistedInSiblingLoop * Reverse the loop order * cleanup and jit-format * Revert "Minor fix to display IG01 weight correctly" This reverts commit 757120e863b2da188db2593da1b7142fd1ecf191. * simplify code * Remove m_hoistedVNInSiblingLoop * Add back ResetHoistedInCurLoop Fix igWeight * Remove reversal of loop processing order * jit format * Experimental: Also generate PerfScore: * review feedback * fix the superpmi script * Revert superpmi asmdiffs change * Rename method * Add a comment * Delete GTF_ASSERTION_PROP_LONG (#70521) * Convert exception help context parsing to managed (#70251) * Move help link parsing to managed * Cleanup wtoi and nativeIsDigit * Fix metasig declaration * Guard GetHelpContext under FEATURE_COMINTEROP * Remove definition of GetHelpLink and guard more methods under cominterop * DWORD should be uint * Add help context marshaling test * Adjust marshaling test * Fix #ifdef with ILLink * Fix method signature mismatch * Specify string marshaling * Throwing test should not test successful HRESULT * Implement ISupportErrorInfo * Test interface in InterfaceSupportsErrorInfo * Delete tests for .NET Framework Xsltc.exe tool (#70706) * Use regex matching for Xsltc test baseline files * Delete xsltc.exe tests entirely * Reenable C4244 in repo (#70026) * Reenable 4244 warning for Mono. * Enable compiler errors for gcc/clang. * Fix issues enabling -Werror=implicit-int-conversion * Revert turning on implicit-int-conversion as error. This check was triggering failures on parts of the PAL that require additional scrutiny beyond the scope of this work. * Add SlidingWindow and FixedWindow to RateLimitPartition (#68782) * align GC memory load calculation on Linux with Docker and Kubernetes (#64128) * align memory load calculation in GC with Docker and Kubernetes * pass inactive file field name as a parameter * [wasm] Fix Debug configuration builds (#70683) * Fix cmake error ``` Manually-specified variables were not used by the project: CONFIGURATION_WASM_OPT_FLAGS ``` * Build the interpreter with -O1 on Wasm in Debug configs Otherwise `interp_exec_method` and `generate_code` can easily overflow the stack in some browsers with even a few recursive calls (for example during .cctor initializaiton) * [wasm] Make runtime_is_initialized promise callbacks one-shot (#70694) * [wasm] Make runtime_is_initialized promise callbacks one-shot Throw if runtime_is_initialized_resolve or runtime_is_initialized_reject is called more than once * Add a slightly generalized GuardedPromise object Protects against multiple-resolve, multiple-reject, reject after resolve and resolve after reject. Does not protect against the executor throwing. * Do not use ExecutableMemoryAllocator on 64 bit platforms if default base address usage is requested (#70563) * [wasm][debugger] Implement get bytes from loaded_files using debugger protocol. (#69072) * Implement get bytes from loaded_files using debugger protocol. * fix pdb size == nul * Adressing @radical comments. * Fix build. * fix compilation * Addressing @radical comments. Co-authored-by: Ankit Jain * Add doc on Unix temporary file security practice (#70585) * Add doc on Unix temporary file security practice * Update unix-tmp.md * Update unix-tmp.md * Add example permissions encoding * Update docs/design/security/unix-tmp.md Co-authored-by: Dan Moseley * Update unix-tmp.md Co-authored-by: Dan Moseley * ConfigurationBinder.Bind on virtual properties duplicates elements (#70592) * ConfigurationBinder.Bind on virtual properties duplicates elements * simplify GetAllProperties * return array instead of list * Obsolete AssemblyName.CodeBase, AssemblyName.EscapedCodeBase (#70534) * JIT: Enable JitConsumeProfileForCasts by default (#69869) * Fix AttributePresence in composite mode (#70737) According to my comparative perf measurements composite framework spends about 5M more instructions in the method coreclr.dll!CMiniMdTemplate::SearchTableForMultipleRows(CMiniColDef sColumn) I tracked this down to the R2R table AttributePresence which is used to speed up attribute queries against the ECMA metadata model. In composite mode we were putting the table in the image header, not component header, and so the runtime was unable to locate it. This change fixes generation of the table in Crossgen2; I have verified that with this change I no longer see the 5M outlier. Thanks Tomas * Handle mis-sized structs in ARM/64 `PUTARG_SPLIT` codegen (#70249) * Add a test * Fix out-of-bounds loads in ARM/64's "genPutArgSplit" * Split the test out * Refactor how implicit byrefs are morphed (#70243) * Refactor implicit by-refs morphing Move it to "fgMorphLocal". Enabled folding in "LocalAddressVisitor". * Add FEATURE_IMPLICIT_BYREFS And use it in all the necessary places. Resolves the TP regression on Unix x64, turning it into a TP improvement. * Add a zero-diff quirk * Do not change `gtRetClsHnd` in `impNormStructVal` (#70699) * Do not change "gtRetClsHdl" in "impNormStructVal" Doing so leads breaking the proper ABI handling for the call. * Add a test * Support `PUTARG_STK(STRUCT LCL_VAR/LCL_FLD)` on ARM/64 (#70256) * Separate out LowerPutArgStk Call it from "LowerArg" instead of "ContainCheckCallOperands", as it does more than just containment analysis. * Support "PUTARG_STK(STRUCT LCL_VAR/LCL_FLD)" on ARM/64 To test this, transform "OBJ(LCL_VAR|FLD_ADDR)" to "LCL_FLD" on lowering. This additionally simplified the codegen code as it doesn't have to support two representations of the same thing. * Support `PUTARG_STK(STRUCT LCL_VAR/LCL_FLD)` on x86/Unix x64 (#70702) * Add GenTree::GetLayout * x86/Unix x64: lowering * x86/Unix x64: "genConsumePutStructArgStk" * x86/Unix x64: "genStructPutArgUnroll" * x86/Unix x64: codegen asserts * x86: "genStructPutArgPush" * Unix x64: "genStructPutArgPartialRepMovs" * Allow `TYP_STRUCT` `LCL_FLD` on the RHS of block copies (#70633) * Delete the unused "GTF_USE_FLAGS" It used to indicate that a branch operation didn't need to materialize its operand and could just "use flags" instead, but that purpose has long been lost now that we have explicit SETCC nodes in lowering. * Make GTF_DONT_EXTEND a shared flag So that it can be used for "LCL_FLD" as well as "GT_IND". No diffs. * Enable TYP_STRUCT on the RHS * fgMorphBlockOperand * Tweak TYP_STRUCT LCL_FLD costs Model it as two load, like OBJ. Note we could be more precise here, by using the register type of the layout. For now, we defer. * Block CSE Preserve previous behavior to avoid diffs. * Revert "Fix usage of GSS_KRB5_CRED_NO_CI_FLAGS_X (#70447)" (#70747) This reverts commit 84f7cad00ad834c365b5cd1297e1166525146b50. * Add note about backward branch constraints to ECMA-335 augments (#70760) * [NativeAOT] Enabling return address hijacking on ARM64 Windows (#70740) * Enabling return address hijacking on ARM64 Windows * pass right flags to the GcInfoDecoder * Fix value numbering of HWI loads (#70621) * Fix numbering of HWI loads Take into account all operands and describe the exception sets precisely. * Add a test * Recast the check * Small MsQuicStream refactorings (#70433) * Inline state transition helpers Fixes #55437 * Add high level comments for HandleEventReceive and ReadAsync * Updating HWIntrinsicInfo::lookupId to not accelerate Vector256 APIs when AVX2 is unsupported (#70686) * Updating HWIntrinsicINfo::lookupId to not accelerate Vector256 APIs when AVX2 is unsupported * Fixing a check in lookupId to properly negate the condition * Ensure the special-cased EA_32BYTE constants only happen when AVX/AVX2 are supported * Fixing a bad assert in morph * Dsiable CertificateValidationRemoteServer.ConnectWithRevocation_WithCallback on Android (#70768) * NativeAOT Unlock assignability comparison in reflection-free (#70726) * NativeAOT Unlock assignability comparison in reflection-free Closes #69960 * Document support for `IsAssignableFrom` * Document support for `IsInstanceOfType` * Document `IsAssignableTo` * Add suggestion from Michal * Update src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeTypeInfo.cs Co-authored-by: Michal Strehovský * Remove whitespaces Co-authored-by: Michal Strehovský * [Mono] Fix C4018 round I (#70417) * First round of change of fixing C4018 * Address part of review feedback * Change the type of idx to unsigned for `effective_table_slow` * Add idx range check after the type was changed * Address review feedback for `class-init.c` * Change the return type of `*table_num_rows*` to `guint32`. Deal with the consequence of return type change of `table_info_get_rows`. Correct the type of a few local variables which store the return of `mono_metadata_token_index`. * Update return type * Address review feedbacks of metadata.c * Fix native crash * Make counter private to for-loop * Address review feedbacks * Address review feedbacks * Fix race condition in LoaderAllocator::CompareExchangeValueInHandle (#70765) The method was not actually using interlocked operation. It made it possible for multiple different values to win. Fixes #70742 * Enable redirection on arm64 (#70769) * Handle HW exceptions on Windows without redirection (#70428) This change modifies the way hardware exceptions are propagated from the vectored exception handler. Until now, runtime was returning from the vectored exception handler with instruction pointer in the context set to an asm helper. That redirected the thread to that helper and we have raised an exception from its call chain. While working on CET support, it was found that propagating exceptions from the vectored exception handler directly works just fine. So this change makes it work that way for all Windows targets. * Predicate for valid Tracker Reference is inverted (#70709) * Predicate for valid Tracker Reference is inverted * Fix test to not inline wrapper creation function. * JIT: Enable addressing modes for gc types (#70749) * JIT: Faster long->int overflow checks (#69865) * Update .net version for asp.net spmi collection script (#70778) * Enable IlcTrimMetadata by default (#70201) Enables more aggressive metadata stripping by default. In this mode, the AOT compiler only generates reflection metadata for artifacts that were deemed reflection-visible by either dataflow analysis, or user inputs. Previously we would consider everything that got generated reflection-visible. * Change the defaults within the compiler (making the conservative mode opt-in). * Add tests for scenarios in https://github.com/dotnet/runtimelab/issues/656 (resolves dotnet/runtimelab#656). * Update tests * Do more marking where it was necessary * Remove GSS_KRB5_CRED_NO_CI_FLAGS_X code (#70772) The support for building with GSS_KRB5_CRED_NO_CI_FLAGS_X was broken for quite some time. Attempts to reenable it failed due to bug in the krb5 GSSAPI implementation resulting in invalid memory accesses. * Make ConnectWithRevocation_StapledOcsp more resilient to being slow * Upgrade SDK to Preview 5 (#70117) Upgrade to released Preview 5 build * Find&replace FastInterlock* with Interlocked* (#70784) FastInterlock* operations were #defined as aliases to regular Interlock* operations. Deleted the FastInterlock* aliases and replaced usage with Interlocked* operations. * JIT: rework optCanonicalizeLoop (#70792) Rework loop canonicalization in anticipation of extending it to handle non-loop edges like those seen in #70802 (details in #70569). The code to fix up flow out of `h` was not needed and has been removed. We now assert upstream that no such fix up will be needed. * Avoid infinite loop in case of heap corruption (#70759) Co-authored-by: Juan Hoyos Co-authored-by: Noah Falk * [wasm][debugger] Remove workaround to get pauseOnExceptions setting (#70748) * Add SubstitutionParser that uses XPath Navigator into NativeAOT (#64671) * Add end-to-end test for NTLM/Negotiate authentication against fake server (#70630) * Add end-to-end test for NTLM/Negotiate authentication against fake server * Simplify the test since HttpClientHandler is always SocketsHttpHandler for the test environment * Fix test condition * Remove extra comment * Enable ThreadAbort with CET enabled via the QueueUserAPC2 (#70803) This change makes ThreadAbort work when CET is enabled. Instead of thread redirection, it uses the new user mode APC mechanism to get a thread to a handler and then throws the ThreadAbortException from there if the thread was interrupted at a safe location. I have verified it works using mdbg tests and also by manual testing in the Visual Studio 2022 using a test app that creates an instance of classes with properties containing infinite loop, wait on a lock, wait on a handle, infinite loop inside of a lock and infinite loop in finally. For the testing, I've enabled this separately from the CET so that the missing support for CET in the debugger code doesn't cause troubles. So we could enable this without CET enabled too, but I'd prefer doing that separately. * Test additional NativeAOT Lib testing (#70212) * Test additional NativeAOT Lib testing * more libraries to un nativeaot rolling build * FB * FB2 * only write results file if specified in args * excluding failing tests * oops, missed pull before a forced push * excluding some recently added tests that fail * fix typo with end element * FB * Fix emitDispJumpList for Arm64 (#70542) * fix jitdump * Fix arm build * Another format * Fix regression in runtime-jit-experimental (#70797) The newly-introduced `emitRemoveJumpToNextInst` optimization caused a regression when hot/cold-splitting, where jumps from the last hot instruction to the first cold instruction were erroneously removed. This is fixed by disabling the `isRemovableJmpCandidate` flag for branches between hot/cold sections. On an unrelated note, a JIT dump message has been added to indicate stress-splitting is occurring. * JIT: relax fwd sub restriction on changing class handle (#70587) For HW SIMD types, at least. Fixes #64879. * Use LastIndexOf in ZipArchiveEntry.GetFileName_Unix (#70701) There's not particularly good reason to open-code the loop here. * Update dogfooding instructions (#70833) - Delete note about multilevel lookup. It is not relevant anymore. - Fix nightly feed url to net7 - Replace .NET Core with just .NET * Add icon to dotnet.exe on Windows (#70578) * Add two new stages to prepare for our new custom type marshalling design. (#70598) * Simplify `Environment.IsWindows8OrAbove`. (#70818) * Simplify Environment.IsWindows8OrAbove. Since .NET 5, the regular Windows version detecton code always returns the correct version. * Remove two unused interop files. * Delete redundant aliases for primitive types (#70805) * Add limited support for LocalCertificateSelectionCallback for QUIC (#70716) * Inline state transition helpers Fixes #55437 * Add high level comments for HandleEventReceive and ReadAsync * [QUIC] Call `LocalCertificateSelectionCallback` to get client certificate * Code review feedback * JIT: Optimize range checks for X >> CNS and for short/byte indices (#67141) Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> * Tighten checks in `areArgumentsContiguous` (#70829) * Tighten checks in "areArgumentsContiguous" * Add a test * Narrow cast fix (#70518) * Added genActualTypeSize. Remove narrow cast if the actual type sizes are the same * Trying to fix build * Fixing build * Removed genActualTypeSize. Using genActualType instead * Added helper function * Comments * Moving back to morph * Removing part of the test * Added fgOptimizeCastOnAssignment * Fixing build * Removing extra bits * Removed fgIsSafeToRemoveIntToIntCastOnAssignment, inlining the implementation, adding extra logic when actual types are not the same * [wasm] Disable WBT test failing on windows (#70808) Issue: https://github.com/dotnet/runtime/issues/70675 * Enable IDE1005 (Delegate invocation can be simplified) (#70522) * Disable long running test (#70843) * [wasm] Enabled WriteToReadOnly tests - emscripten bug got fixed (#70814) Fixes #53021. Enabled tests from #53021 - they are passing now because issue reported by @radekdoulik got fixed: https://github.com/emscripten-core/emscripten/issues/14299. * Use IndexOf{Any} in a few more places (#70176) * Use IndexOf{Any} in a few more places * Address PR feedback * Fix corerun for assemblies with mismatched filename (#70800) corerun gracefully handled filename not matching the assembly name. Handling of this case regressed in #68186. This change is fixing the regression. Fixes #68455 * Fix a few Stream-related issues in System.Net.Http (#70731) * Fix a few Stream-related issues in System.Net.Http * Put back WriteTimeout * Fix tests * Catch (more) mismatched args in `fgMorphArgs` (#70846) * Catch (more) mismatched args in "fgMorphArgs" * Add a test * [coop] fix coop suspend timeout cue card (#70828) the BLOCKING_SUSPEND_REQUESTED state is treated as suspend in full coop mode (the thread keeps running, but by definition it's not allowed to access managed resources and it will self-suspend if it tries to enter GC Unsafe mode by calling a runtime API or managed code). It is bad in hybrid suspend mode (the thread should be preemptively suspended, but we timed out before the signal handler had a chance to run). The corresponding suspension logic in the code is: https://github.com/dotnet/runtime/blob/3fc61ebb562afc327a8fc6de5c82d76e86bf6f5d/src/mono/mono/utils/mono-threads.c#L1149-L1158 * Fixing the handling of Positive NaN in Math.Min for float/double (#70795) * Adding tests validating Positive NaN for Max, MaxMagnitude, Min, and MinMagnitude * Fixing the handling of Positive NaN in Math.Min for float/double * Fixing the Max/Min code comments to use greater and lesser * Adding a code comment clarifying the sign toggling behavior * JIT: break loop canonicalization into two stages (#70809) For a given loop, we need to separate out the true backedge, any non-loop backedges, and any inner loop backedges so that they all target distinct blocks. Otherwise, we may violate assumptions that the loop entry dominates all blocks in the loop and that all backedges that reach top come from within the loop. This seems simplest to do with two rounds of canonicalization, one that moves the non-loop edges, and another that moves the true backedge. Fixes #70802. * Use `Array.Empty()` in `System.Reflection.Metadata`. (#70862) It is now available in all frameworks it targets. * Delete StaticallyLinked property from Microsoft.NETCore.Native.Unix.props (#70854) This option has many issues. Anybody trying to experiment with static linking can add `` into the local file. * Restore ArchivingUtils.AttemptSetLastWriteTime (#70617) * Fix GC stress failure in LoaderAllocator::CompareExchangeValueInHandle (#70832) InterlockedCompareExchangeT has to be called on a raw Object* to make the GC stress infrastructure happy. * Small performance cleanups in S.S.Cryptography * ARM64 - Optimize `i % 2` (#70599) * Assign proper VNs to "shared constant" CSE defs (#70852) * Assign proper VNs to shared CSE defs They must be those of the original expression, not the "base" constant CSE creates. * Add a test * Enable IDE0054 (Use compound assignment) (#70564) * Enable IDE0054 (Use compound assignment) * Update src/libraries/System.Data.Common/src/System/Data/Common/StringStorage.cs Co-authored-by: Tanner Gooding Co-authored-by: Tanner Gooding * Use new byte[] span optimization in a few more places (#70665) * Use new byte[] span optimization in a few more places Separated out of larger change to use CreateSpan (these don't rely on that). * Address PR feedback * Improve TLS1.3 detection in registry for QUIC (#70730) * Improve TLS1.3 detection in registry for QUIC * Split client and server detection * Code review feedback * Generate method bodies for delegate Invoke methods (#70883) There is a dataflow warning suppression in System.Linq.Expressions that assumes we'll always have an invocable method body for delegate Invoke method. We need one in IL. We don't in native code. Emulate what IL Linker does and generate a method body. This is a size regression. Suppression: https://github.com/dotnet/runtime/blob/3b2883b097a773715ca84056885e0ca1488da36e/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/TypeUtils.cs#L906-L912 Fixes #70880. * Avoid crashing on unresolved dependencies (#70871) Fixes #70815. * Enable IDE0020 (Use pattern matching) (#70523) * Enable IDE0020 (Use pattern matching) * Update src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs Co-authored-by: Buyaa Namnan * Update variable naming Co-authored-by: Buyaa Namnan * Fix failure building two libraries tests (#70881) Microsoft.CSharp was hitting an issue due to a vararg constructor. We don't support varargs. They shouldn't make it into the dependency graph. We are already checking in many places. We were erroneously thinking a vararg constructor with no mandatory arguments is a default constructor. Runtime.InteropServices were crashing because we got a MulticastDelegate type into a codepath that expects a MulticastDelegate descendant. * Use hash/hmac one shots in NTLM (#70857) Co-authored-by: Stephen Toub * Unpin locals, attempt 2 (#70655) Contributes to #40553 * Replace a few instances of PtrToStructure with more efficient marshalling (#70866) * Fix for timer scheduling happening on the incorrect thread when wasm threading is enabled (#70863) * Add event to capture min/max threads (#70063) Event ThreadPoolMinMaxThreads added. Parameters are: ushort MinWorkerThreads ushort MaxWorkerThreads ushort MinIOCompletionThreads ushort MaxIOCompletionThreads ushort ClrInstanceID It is fired in the ThreadPool constructor and in the SetMinThreads/SetMaxThreads functions. * [wasm] Add support for per-project customization of helix work items (#70461) * [wasm] Add support for per-project customization of helix work items Currently, for sending tests to helix: 1. the project binaries are zipped, as part of the project build 2. then separate helix targets files build that adds helix items for those zip files. - for wasm, we test with multiple 'scenarios' - like v8, browser, and nodejs. - so, 3 helix work items are submitted per zip file - If a test project needs to have any customizations, for example, for testing crypto with a managed implementation, and subtlecrypto, which would require: - passing different arguments to xharness, in case of managed, and subtlecrypto - and this should be done only for the browser case - Currently, this would need this would need to be done in `sendtohelix-wasm.targets` special casing for the test project, and scenario. - We add support for importing `$(ProjectName).helix.targets`, and calling a special target in that to add helix items, as needed. - This targets file can be set in the test project like: ```xml wasm.helix.targets ``` - it will get deployed next to the zip file, and picked up automatically ```xml <_CryptoProjectName>System.Security.Cryptography.Tests System_Security_Cryptography_Tests_Targ et $(TestArchiveTestsDir)$(_CryptoProjectName).zip $(HelixCommand) $(_workItemTimeout) $(TestArchiveTestsDir)$(_CryptoProjectName).zip $(HelixCommand) $(_workItemTimeout) set "WasmXHarnessArgs=--web-server-use-cors" export "WasmXHarnessArgs=--web-server-use-cors" ``` - The targets file *must* have these: - a property named like `System_Security_Cryptography_Tests_TargetName`, for a test project named `System.Security.Cryptography.Tests` - if this property is not set, then the default behavior of adding work items will run - The target should add any items it needs to to `@(HelixWorkItem)`. - Examples of adding these can be seen in `sendtohelix*` project files - Remember that all these properties, and targets get imported into the msbuild *global* namespace, so make sure to use unique names to avoid conflicts with other test projects. Future work: this commit only enables it for wasm/library tests, but it should be easy to extract it out, but needs some testing. * [wasm] Helix: test with, and without subtle crypto * disable non-wasm builds * address review feedback * Address review feedback * Fix typo * Revert "disable non-wasm builds" This reverts commit 7ef99e81f82200189dd3f61eeaf00d6ca4ced6d4. * Update src/libraries/System.Security.Cryptography/tests/wasm.helix.targets Co-authored-by: Eric Erhardt * Address review feedback * remove debug spew * Change the way helix extension targets are discovered. The new approach: To run a custom project specific target for adding/editing @(HelixWorkItem): - In the project add: `wasm.helix.targets` - This file gets copied next to the test archive as $(MSBuildProjectName).helix.targets - In this `wasm.helix.targets` file, add to $(HelixExtensionTargets) to run your custom target ```xml $(HelixExtensionTargets);_AddHelixCrypoItems ``` - The extension target will be called after the default items are added to `@(HelixWorkItem)`. - Useful properties to condition on: $(Scenario), $(IsRunningLibraryTests) - And add to, change, or remove from @(HelixWorkItem) Example: ```xml $(TestArchiveTestsDir)$(_CryptoProjectName).zip $(HelixCommand) $(_workItemTimeout) $(_CryptoProjectName) $(TestArchiveTestsDir)$(_CryptoProjectName).zip $(HelixCommand) $(_workItemTimeout) $(_CryptoProjectName) set "WasmXHarnessArgs=%WasmXHarnessArgs% --web-server-use-cop" export "WasmXHarnessArgs=$WasmXHarnessArgs --web-server-use-cop" <_CryptoHelixItem Include="@(HelixWorkItem)" Condition="$([System.String]::new('%(HelixWorkItem.Identity)').EndsWith('-$(_CryptoProjectName)'))" /> ``` * cleanup * Move WBT specific stuff into the target too. This will make it simpler to move it off into a targets file later * fix build * fix libtests * fix wbt * [wasm] Bump helix timeout to 90mins for debugger tests on windows Co-authored-by: Eric Erhardt * Fix bug in Tar preventing extraction of hardlinks or entries starting with `.\` (#70853) * Add PlatformDetection.SupportsHardLinkCreation property. * Fix how paths are combined/joined and sanitized on extraction, to ensure paths with redundant segments get properly handled. * Add tests that verify archives with entries whose paths start with .\, including the root folder itself. * Re-enable the hardlink test, condition it to not run if platform does not support extraction of hardlinks. * Remove unnecessary test - This same code is already being tested by TarReader_ExtractToFile_Tests.ExtractEntriesWithSlashDotPrefix * Reuse test code that retrieves memory stream. * Bump test data package version * Add missing typeof(PlatformDetection) in ConditionalFact Co-authored-by: carlossanlop * Remove #define Sleep (#70868) * Remove #define Sleep * Fix ICorDebugFunction2::GetVersionNumber for arm32. (#69901) * Replace the remaining uses of Marshal.PtrToStructure in core networking (#70900) * Rename ICMP interop to match Windows SDK names * Add support for delegate GDV and method-based vtable GDV (#68703) Add support for instrumenting delegate calls and vtable calls into method handle histograms. Use these histograms to do GDV for delegate calls and also support method-based GDV for vtable calls. For instrumentation we now support class probes at interface call sites, method probes at delegate call sites and both class probes and method probes at vtable call sites. For vtable calls, when turned on, instrumentation produces both histograms as PGO data so that the JIT can later make the choice about what is the best form of guard to use at that site. For guarding, there are some things to take into account. Delegate calls currently (practically) always point to precode, so this PR is just guarding on getFunctionFixedEntryPoint which returns the precode address, and this is generally quite cheap (same cost as class-based GDV). That's the case for delegates pointing to instance methods anyway, this PR does not support static methods yet -- those will be more expensive. For vtable calls the runtime will backpatch the slots when tiering, so the JIT guards the address retrieved from the vtable against an indirection of the slot, which is slightly more expensive than a class-based guard. Currently the instrumentation is enabled conditionally with COMPlus_JitDelegateProfiling=1 (for delegates) and COMPlus_JitVTableProfiling=1 (for vtable calls). Currently delegate profiling is turned on by default while vtable profiling is off by default. * Use ArgumentNullException.ThrowIfNull in a few more places (#70897) * Append the function pointer type (#70923) The issue here was the recursion into PrettyPrintSigWorkerInternal that would reset the buffer. Now, we pass in a new buffer and append it when we return. * [main] Update dependencies from dotnet/runtime dotnet/icu dotnet/xharness dotnet/runtime-assets dotnet/emsdk dotnet/roslyn-analyzers (#70476) * Update dependencies from https://github.com/dotnet/runtime-assets build 20220608.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 7.0.0-beta.22281.1 -> To Version 7.0.0-beta.22308.1 * Update dependencies from https://github.com/dotnet/emsdk build 20220608.2 Microsoft.NET.Workload.Emscripten.Manifest-7.0.100 From Version 7.0.0-preview.6.22281.1 -> To Version 7.0.0-preview.6.22308.2 * Update dependencies from https://github.com/dotnet/xharness build 20220610.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 1.0.0-prerelease.22305.1 -> To Version 1.0.0-prerelease.22310.1 * Revert "Update dependencies from https://github.com/dotnet/emsdk build 20220608.2" This reverts commit bbb4e156ddbad8a2cb7b604246214272085b6622. * Update dependencies from https://github.com/dotnet/icu build 20220609.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 7.0.0-preview.6.22306.1 -> To Version 7.0.0-preview.6.22309.1 * Update dependencies from https://github.com/dotnet/emsdk build 20220608.2 Microsoft.NET.Workload.Emscripten.Manifest-7.0.100 From Version 7.0.0-preview.6.22281.1 -> To Version 7.0.0-preview.6.22308.2 * Update dependencies from https://github.com/dotnet/runtime-assets build 20220610.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 7.0.0-beta.22281.1 -> To Version 7.0.0-beta.22310.1 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20220610.1 Microsoft.CodeAnalysis.NetAnalyzers From Version 7.0.0-preview1.22302.1 -> To Version 7.0.0-preview1.22310.1 * Update dependencies from https://github.com/dotnet/runtime build 20220612.5 Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.DotNetHost , Microsoft.NETCore.DotNetHostPolicy , Microsoft.NETCore.ILAsm , runtime.native.System.IO.Ports , System.Text.Json From Version 7.0.0-preview.6.22305.4 -> To Version 7.0.0-preview.6.22312.5 * Update dependencies from https://github.com/dotnet/icu build 20220613.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 7.0.0-preview.6.22306.1 -> To Version 7.0.0-preview.6.22313.1 * Update dependencies from https://github.com/dotnet/xharness build 20220613.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 1.0.0-prerelease.22310.1 -> To Version 1.0.0-prerelease.22313.1 * Update dependencies from https://github.com/dotnet/runtime-assets build 20220613.1 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 7.0.0-beta.22281.1 -> To Version 7.0.0-beta.22313.1 * Update dependencies from https://github.com/dotnet/emsdk build 20220613.1 Microsoft.NET.Workload.Emscripten.Manifest-7.0.100 From Version 7.0.0-preview.6.22281.1 -> To Version 7.0.0-preview.6.22313.1 * [wasm] Wasm.Build.Tests: Disable strict version checks for emcc Due to the way we have to update `dotnet/emsdk`, and get the update PRs in `runtime`, the emsdk version can be mismatched. For example, if `dotnet/emsdk` has already updated to `3.1.12`, but `dotnet/runtime` is still on `3.1.7`. This is an expected scenario while working on updating to a newer emscripten. The version mismatch will still show up, but as a warning now. * Update dependencies from https://github.com/dotnet/xharness build 20220614.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 1.0.0-prerelease.22310.1 -> To Version 1.0.0-prerelease.22314.1 * [wasm] Wasm.Build.Tests: Update Skiasharp reference The skiasharp dependent tests fail with: `error : undefined symbol: _ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv`. Update the reference to the latest package which added a binary compiled for `3.1.7`. * [wasm] Workaround a test failure in WBT Currently, there is a mismatch between emsdk versions with the workload emscripten packs using `3.1.12`, and the runtime being built with `3.1.7`. And that is causing `Wasm.Build.Tests.NativeLibraryTests.ProjectUsingSkiaSharp` to fail with: ``` EXEC : error : undefined symbol: _ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv (referenced by top-level compiled C/C++ code) [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : warning : Link with `-sLLD_REPORT_UNDEFINED` to get more information on undefined symbols [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : warning : To disable errors for undefined symbols use `-sERROR_ON_UNDEFINED_SYMBOLS=0` [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : warning : __ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : error : undefined symbol: _ZNKSt3__221__basic_string_commonILb1EE20__throw_length_errorEv (referenced by top-level compiled C/C++ code) [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : warning : __ZNKSt3__221__basic_string_commonILb1EE20__throw_length_errorEv may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] EXEC : error : Aborting compilation due to previous errors [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] emcc : error : '/datadisks/disk1/work/B1420981/w/ACC90933/e/dotnet-workload/packs/Microsoft.NET.Runtime.Emscripten.3.1.12.Node.linux-x64/7.0.0-preview.6.22313.1/tools/bin/node /datadisks/disk1/work/B1420981/w/ACC90933/e/dotnet-workload/packs/Microsoft.NET.Runtime.Emscripten.3.1.12.Sdk.linux-x64/7.0.0-preview.6.22313.1/tools/emscripten/src/compiler.js /datadisks/disk1/work/B1420981/t/tmp44tn7y2d.json' failed (returned 1) [/datadisks/disk1/work/B1420981/w/ACC90933/e/blz_nativeref_aot_Debug/blz_nativeref_aot_Debug.csproj] ``` This commit adds a temporary workaround to ignore the undefined symbols for this specific test. And this should be removed when runtime is updated to `3.1.12` . Co-authored-by: dotnet-maestro[bot] Co-authored-by: Alexander Köplinger Co-authored-by: Larry Ewing Co-authored-by: Ankit Jain * Harden for null byrefs (#70317) * Remove enum_flag_Unrestored usage in boxing stubs. * Add AND instruction (21h) to x86 decoder. * Update mono for null ref in interpreter paths. * Disable test on llvmfullaot and wasm * Handle null destination for intrinsics. * Use u8 in a few more places (#70894) * Use u8 in a few more places * A few more u8s * Enable lib tests that used to fail with GC issues (#70831) * enable lib tests that used to fail with GC issues * excluding linq parallel test since that doesn't build * Threading.Thread tests have issues * Excluding new test failures * Remove some dead code / branches (#70146) * Remove some dead code / branches Some signal amidst the noise in an lgtm.com report. * Address PR feedback * superpmi.py: Add `-jitoption` for asmdiffs (#70939) The new `-jitoption` option passes the argument options to both baseline and diff compilers. This is a convenience option: there already is `-base_jit_option` and `-diff_jit_option` to specify passing options to either baseline or diff. The name of the option is the same as that used for `replay`. * EventLogException is missing the original win32 error code (#70629) * Enable IDE0071 (Simplify interpolation) (#70918) * Enable IDE0100 (Remove redundant equality) (#70896) * Enable IDE0065 (Misplaced using directive) (#70919) * Optimization for full range checks (#70145) (#70222) * Update C# compiler (#70947) Brings in support for required members * Allow ValueListBuilder to work with empty scratch spans (#70917) * Enable IDE0030 (Use coalesce expression) (#70948) * Do not reuse implicit byrefs for by-value args (#70955) * Do not reuse implicit byrefs for by-value args * Add a test * Enable `TYP_STRUCT` `LCL_VAR/LCL_FLD` call args on Windows x64 (#70777) * Fix forward sub * Enable folding in local morph * Morph: TYP_STRUCT LCL_FLD * Make SuperPMI more explicit about JIT in error messages (#70938) This makes it easier to figure out which JIT failed in asmdiffs scenarios. e.g., ``` [10:40:50] ERROR: Method 3673 of size 3107 failed to load and compile correctly by JIT2 (C:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\clrjit_universal_arm64_x64.dll). [10:40:50] ERROR: Method 3673 of size 3107 failed to load and compile correctly by JIT1 (C:\gh\runtime2\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\clrjit_universal_arm64_x64.dll). ``` * Fix illumos-x64 build (#70956) * Disable W^X on macOS under Rosetta emulation (#70912) * Disable W^X on macOS under Rosetta emulation Apple has informed us that double mapping doesn't work properly on Rosetta emulation. This change disables W^X if Rosetta is detected. * Reflect PR feedback * Add support for randomized guard stack cookies (#70806) The compiler was generating GS cookies, but the cookie was always an ASCII encoding of "Hi, mom!". Make the cookie properly per-process randomized. The randomization algorithm is same as in the CoreCLR VM. Fixes #70071. * Fixes #64159 - JsonSerializerContext source generation fails with keyword identifiers (#66876) * Fixes #64159 - initial implementation * Tidy up, and add test for ignored reserved-keyword-named property * PR feedback - use same approach as logging generator * PR feedback * Update src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> * PR feedback - rename ExactNameSpecifiedInSourceCode * PR feedback - use extracted (and renamed) local variable * Remove commented code * Added `IsVerbatimName` as extension method * Support fields with verbatim names (@) * Use alternative method for checking for verbatim names * Uses `SyntaxFacts` to determine if escaping is needed * Remove extension method * Modified source generator test to include a verbatim field * Minor typo Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> * [main] Update dependencies from dotnet/arcade (#70662) Co-authored-by: dotnet-maestro[bot] * Enable IDE0031 (Use null propagation) (#70965) * Fix nullable annotations on MailAddress.TryCreate (#70943) * [QUIC] Removes abstract providers and mock from S.N.Quic (#70421) * Removed abstract providers and mock from S.N.Quic * Removed provider and replaced with statics on Listener and Connection * Added assert * Stop wrapping SIMD nodes in OBJs (#70888) * Upstream coreclr and pal changes to support powerpc (ppc64le) architecture (#69105) * coreclr pal layer chanegs. * Updated the system arch for power architecture. * Fixed the failing PAL SXS exception_handling test case * replaced gint with gint64 to avoid overflow and this has fixed the segmentation fault issue. * coreclr pal layer chanegs. * Fixed the failing PAL SXS exception_handling test case * coreclr pal layer chanegs. * Updated the system arch for power architecture. * Fixed the failing PAL SXS exception_handling test case * replaced gint with gint64 to avoid overflow and this has fixed the segmentation fault issue. * coreclr pal layer chanegs. * Fixed the failing PAL SXS exception_handling test case * Removing intsafe.h file as main does not have this file now.(Already removed in commit 27195f670937c7e21ab68a806396f9d17c57231a) Co-authored-by: Alhad Deshpande * Collections contain stale object IDs (#70924) It looks like the collections contain stale ObjectID values. These collection should be purged between GCs. * Minor refactoring for `UpgradeToRegexGeneratorAnalyzer` (#70767) * Fix arm64 funclet frame type 5 (#70922) * Fix arm64 funclet frame type 5 * Add code to stress arm64 funclet frame type 5 This can be forced using `COMPlus_JitSaveFpLrWithCalleeSavedRegisters=3`, or will be enabled under stress. * Add a regression test * Fix funclet frame type 5 alignment calculation * Fix a couple bugs; improve documentation 1. Improve the frame shape pictures, especially for arm64 funclet frames. Include the MonitorAcquired element and OSR pad. 2. Fix bug for `SP_to_PSP_slot_delta` for funclet frame type 4 for OSR: don't include osrPad. 3. Fix bug with funclet frame type 5 for `SP_to_FPLR_save_delta` using wrong aligned func size; would be incorrect if one and two SP adjustment full frame aligned sizes are different (e.g., if two SP adjustment required two alignment slots and one SP adjustment thus required none). * Fix default log color behavior when console is redirected (#70504) * JIT: Model string literal objects as invariant and non-GLOB_REF (#70986) * Model string literals as invariant/non GLOB_REF * String literals are never null * Add support for cross module inlining and cross module generic compilation to Crossgen2 (#68919) * Add support for cross module inlining and cross module generic compilation to Crossgen2 - Refactor Module into ModuleBase and Module - The goal is to have allow a subset version of Module which can only hold refs, this is to be used by the manifest module in an R2R image to allow for version resilient cross module references. - Update handling of ModuleBase so that its used everywhere that tokens are parsed from R2R - Remove ENCODE_MODULE_ID_FOR_STATICS and ENCODE_ACTIVE_DEPENDENCY - These were only used for NGEN, and conflict with easy impelmentation for the ModuleBase concept - Remove locking in ENCODE_STRING_HANDLE processing, and tweak comments. Comments applied to the removed ngen based code, and the lock was only necessary for the old ngen thing. - Adjust ComputeLoaderModuleWorker for locating loader module - Follow comment more accurately, to avoid putting every generic into its definition module. This will make R2R function lookup able to find compiled instantiations in some cases. This may be what we want long term, it may not. - Remove MemberRefToDesc map and replace with LookupMap like the other token types. We no longer make use of the hot table, so this is more efficient - Also reduces complexity of implementation of ModuleBase - Build fixup to describe a single method as a standalone blob of data - There are parallel implementations in Crossgen2 and in the runtime - They produce binary identical output - Basic R2RDump support for new fixup - Adjust module indices used within the R2R format to support a module index which refers to the R2R manifest metadata. This requires bumping the R2R version to 6.2 - Add a module index between the set of assembly refs in the index 0 module and the set of assembly refs in the R2R manifest metadata - Adjust compilation dependency rules to include a few critical AsyncStateMachineBox methods - Remove PEImage handling of native metadata which was duplicative - Do not enable any more devirtualization than was already in use, even in the cross module compilation scenario. In particular, do not enable devirtualization of methods where the decl method isn't within the version bubble, even if the decl method could be represented with a cross-module reference token. (This could be fixed, but is out of scope for this initial investigation) Make the compilation deterministic in this new model, even though we are generating new tokens on demand - Implement this by detecting when we need new tokens during a compile, and recompiling with new tokens when necessary - This may result in compiling the same code as much as twice Compile the right set of methods with cross module inlining enabled - Add support for compiling the called virtual methods on generic types - This catches the List and Dictionary scenarios - Add command line switches to enable/disable the new behavior - By default the new behavior is not enabled * Implement Vector128 version of System.Buffers.Text.Base64 DecodeFromUtf8 and EncodeToUtf8 (#70654) * Implement Vector128 version of System.Buffers.Text.Base64.DecodeFromUtf8 Rework the SS3 into a Vector128 version, and add Arm64 support. * SSE3 improvements * Remove superfluous bitwise And * Add comment to SimdShuffle * Inline SimdShuffle * Implement Vector128 version of System.Buffers.Text.Base64.EncodeToUtf8 * Ensure masking on SSE3 Change-Id: I319f94cfc51d0542ae4eb11a8d48b3eb8180553f CustomizedGitHooks: yes * Restore asserts and move zero inside the loop * Neater C# code Change-Id: I2cbe14f4228f8035e7d213b5b58815c4eee35563 CustomizedGitHooks: yes * Make SimdShuffle consistent across X64 and Arm64 * Better looking multiply * Use `gtEffectiveVal` for `GT_ADD` op1 in `optCreateAssertion` (#70228) * Initial work for comma hoisting in cse * Formatting * Adding more ops to comma hoisting * Set regnum * Update optcse.cpp * Using effectiveval instead * Convert fallback path of GetCommandLineArgs to managed (#70608) * P/Invoke definition * Use P/Invoke in managed code * Update managed call site * Add test using private reflection * Native command line should be superset of managed Co-authored-by: Jan Kotas * [wasm] Enabled WasmTestOnBrowser run on Windows for Browser. (#70890) * Enabled tests - no timeout with new ems. Keeping disabled tests failing from other reasons. * Added @radical's suggestion. * Test CI- enable test that are throwing in Debug. * [wasm][debugger] Fix side effect on Firefox of getting bytes from loaded_files using debugger protocol (#70990) * Fix 70983 * fix typo * Fix compilation * Add AddSystemd() and AddWindowsService() IServiceCollection extension methods (#68580) * Add AddSystemd() IServiceCollection extension method * Add AddWindowsService() IServiceCollection extension method * Don't default to CWD if in C:\Windows\system32 - instead, when CWD is C:\Windows\system32 Hosting will use AppContext.BaseDirectory. This way Windows apps and services that are launched will work by default. HostApplicationBuilder.ContentRootPath can't be changed after construction, so setting it to a workable default for Windows apps. Co-authored-by: Eric Erhardt Co-authored-by: Martin Costello * Use RemoteExecutor * Update src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs * Skip test on Windows nano server * Respond to PR feedback Co-authored-by: Eric Erhardt Co-authored-by: Martin Costello * [main] Update dependencies from dotnet/runtime dotnet/xharness dotnet/icu dotnet/emsdk (#70991) * Update dependencies from https://github.com/dotnet/runtime build 20220619.5 Microsoft.NET.Sdk.IL , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.DotNetHost , Microsoft.NETCore.DotNetHostPolicy , Microsoft.NETCore.ILAsm , runtime.native.System.IO.Ports , System.Text.Json From Version 7.0.0-preview.6.22312.5 -> To Version 7.0.0-preview.6.22319.5 * Update dependencies from https://github.com/dotnet/xharness build 20220620.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 1.0.0-prerelease.22314.1 -> To Version 1.0.0-prerelease.22320.1 * Update dependencies from https://github.com/dotnet/icu build 20220620.2 Microsoft.NETCore.Runtime.ICU.Transport From Version 7.0.0-preview.6.22313.1 -> To Version 7.0.0-preview.6.22320.2 * Update dependencies from https://github.com/dotnet/emsdk build 20220620.1 Microsoft.NET.Workload.Emscripten.Manifest-7.0.100 From Version 7.0.0-preview.6.22313.1 -> To Version 7.0.0-preview.6.22320.1 Co-authored-by: dotnet-maestro[bot] * Windows/Arm64: Use 8.1 atomic instructions if they are available (#70921) * Use Fast compareexchange, acquire/release * working windows version * remove printf * some more #ifdef * fix some #ifdef * optimize EnterObjMonitorHelperSpin * Remove FastInterlockedCompareExchange64 for now * Add ZipArchiveEntry.IsEncrypted for password-protection detection (#70036) * Add ZipArchiveEntry.IsEncrypted for password-protection detection * Apply suggestions from code review Co-authored-by: David Cantú * Run GenerateReferenceAssemblySource for System.IO.Compression * Revert WriteAsync default parameter value removal * Update DeflateStream.WriteAsync to include the default param value * Revert unrelated change from GenerateReferenceAssemblySource * Revert unrelated change after syncing with GenerateReferenceAssemblySource Co-authored-by: David Cantú * Exposing IRootFunctions.Hypot and IRootFunctions.Root (#71010) * Exposing IRootFunctions.Hypot and IRootFunctions.Root * Adding tests for IRootFunctions.Hypot and IRootFunctions.Root * Add TarEntry conversion constructors (#70325) * ref: Conversion constructors * src: Conversion constructors * tests: Conversion constructors * [wasm] Wasm.Build.Tests: disable tests failing on CI (#71020) * [wasm] Wasm.Build.Tests: disable tests failing on CI .. due to being oomkill'ed. * [wasm] Don't fail the job when firefox tests fail, as they are known to be unstable * Remove allocation in ImmutableArray Builder Sort (#70850) * Remove allocation in ImmutableArray Builder Sort `ImmutableArray.Builder.Sort(Comparison comparison)` allocates a new instance of `Comparer` using `comparison`. Then `ArraySort` allocates a new delegate from `comparer.Compare`. Both allocations can be eliminated by calling `Array.Sort(T[] array, Comparison comparison)` directly. * Sort only valid range of array * Use MemoryExtensions.Sort where available. * Update src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs Fix spelling mistake. Co-authored-by: Eirik Tsarpalis Co-authored-by: Eirik Tsarpalis * [Android] Make sure AdditionalTimeZoneChecks trait is added to xunit-excludes (#70974) The trait is supposed to be included in System.Runtime tests by default, but wasn't because the _withoutCategories property was in tests.props. As a result, the property was resolved before the .csproj properties. This fix moves the property definition to tests.targets. Fixes #70482 * Use LastIndexOfAny in GetFileName_Windows (#71032) * Avoid unnecessary allocations in SanitizeEntryFilePath (#71034) * Fix Ordinal Ignore Case string compare (#71022) * Move allocation of command line argument array to C# (#71021) Also, avoid redundant allocation of managed string for each command line argument. * Add markdown readme for System.Reflection.MetadataLoadContext (#70610) * Create README.md * set red zone size 512 for powerpc64. (#70885) * Ensure consistent reflectability for generic methods (#70977) If we have a method body for `SomeMethod` and `SomeMethod` was decided to be reflection-visible, ensure `SomeMethod` is also reflection-visible. * Implement NegotiateAuthentication API (#70720) * WIP: Add implementation of NegotiateAuthentication Switch System.Net.Http to use NegotiateAuthentication Fix IsCompleted in managed NTLM implementation * WIP: Update error code mapping * Spanify input of GetOutgoingBlob * Update comments * Move NegotiateStreamPal.Encrypt/Decrypt to shared sources. Unix implementation already had them and they get trimmed anyway. * Revert accidental change * Build fixes. * Fix error handling condition * Update error mapping based on HttpListener usage. * WIP: HttpListener test * Move workaround from HttpListener to low-level SSPI code * Fix build * Clean up * Revert "WIP: HttpListener test" This reverts commit 18d7d93f04c93e048efcaca0f3c55c3f1f73516a. * Convert System.Net.Http.FunctionalTests to use NegotiateAuthentication instead of NTAuthentication * Dispose the identity along NegotiateAuthentication * Modify unit tests to use the new API * Add exceptions for invalid inputs/states * Remove tvOS unsupported marker, managed NTLM is used on tvOS * Apply suggestions from code review Co-authored-by: Stephen Toub * Fix typo * Remove reference equality checks from IsNTLM/IsKerberos * Remove NTAuthentication.AssociatedName to make it more obvious which exceptions are thrown * Add comment * Add more tests, handle unsupported protocols * Handle NotSupportedException from NTAuthentication constructor * Add workaround for linker issue * Apply suggestions from code review Co-authored-by: Stephen Toub * Fix IPAddress equality comparison in MsQuicListener (#70979) * Fix IPAddress equality comparison in MsQuicListener * Modify test * Adjust comment * Update src/libraries/System.Net.Quic/tests/FunctionalTests/QuicListenerTests.cs Co-authored-by: Anton Firszov Co-authored-by: Anton Firszov * Fix typo in GC_FORBID doc (#71050) * [mono] Do not generate impossible instantiations for constrained generics in Mono AOT (#70838) This change improves the AOTed code size by reducing the number of generated methods for generics. Fixes https://github.com/dotnet/runtime/issues/54850 * Switch to PREEMPT mode when calling CoTaskMem* APIs (#71031) * Switch to PREEMPT mode when calling CoTaskMem* APIs * Add failfast for COM calls from managed code. Co-authored-by: Jan Kotas * JIT: fix loop alignment issue (#70936) When scanning to figure out which blocks should have alignment padding, we can sometimes encounter a block in a loop before we see the block at the top of the loop.. If so, remove alignment for that loop, otherwise the emitter code handling alignment gets tripped up. Even if the emitter could handle this case, it would be padding with the loop, not before it. The problematic block reordering is done much earlier. At some point we need to revisit this as it is making nonsensical ordering decisions. But we'll tolerate it for now. Fixes #70152. * JIT: Fix reordering of call args on x86 (#70931) On x86 we skipped checking stack arguments for side effects with a comment that such arguments do not need to be evaluated into temps. While this is true a large part of the logic that follows is responsible for evaluating previous arguments into temps, and we must still do this. * Simplify random GDV (#70980) Given that we now have getLikelyClasses that returns all likely classes we can just use a random index into this array. * Add missing call to initiate thread abort with CET (#71053) In my recent PR to make ThreadAbort work with CET enabled, one key line of the change somehow slipped out of the change. This change adds that missing line that actually initiates the thread abort after interruption at a safe point. * Enabling console logger queue length and mode to be configurable (#70186) * Fix SIMD data overallocation (#71043) The JIT was allocating 16 bytes for TYP_SIMD8 static data loads, and marking the data section as requiring 16 byte alignment as well. Fix this to not allocate more than necessary, or over align. * fix: [Wasm] Add missing libicudata.a for native layout (#70682) * JIT: handle case where we are cloning adjacent sibling loops (#70874) We can sometimes see adjacent sibling loops (where L1.bottom == L2.head) and if so, cloning L1 will repurpose L1.bottom and so leave L2 in an inconsistent state. Detect this case during optCanonicalizeLoop, and add an intermediary block to serve as L2's head. Fixes #70569. * JIT: avoid cloning mid-entry loops with multiple non-loop entry preds (#70959) If a mid-entry loop has several non-loop preds, some of them may be edges from enclosing loop constructs that were not recognized as loops on their own. Avoid cloning such loops. We won't do proper invariance anlysis as we are not properly recognizing the extent of the loop as is, and we won't get the flow connnected up properly post cloning (so that the fast loop is proper loop where the entry is dominated by the head). This is a workaround for a fairly rare case. Such loops are never iterable and so we will only try cloning when these loops have an invariant type test. Ideally we would extend loop canonicalization to cover this case, essentially ensuring that all recognized loops have a preheader -- that is, that the entry has just one non-loop predecessor. Currently we do this only for top entry loops. But doing that with our current setup looked more complex and we don't expect to see many of these cases. Closes #70802. * Fixed :scheme header for H/2 with PlaintextStreamFilter (#71057) * [wasm] Migrate to ref/out param while reading data from typed array (#70823) Use js_typed_array_to_array_root in mono_wasm_typed_array_to_array_ref * Renaming files because they don't reflect the IL code used in the tests (#69814) * Renaming files to .template because they reflect the code in the IL and also don't work * Rename valuetypes.cs to valuetypes.cs.template * Changing all the CS files that doesn't reflect the IL file * Revert "Add support for cross module inlining and cross module generic compilation to Crossgen2 (#68919)" (#71076) This reverts commit 18ec279e4be9193ce838d73e7d850e3c798991fd. * Use crypto.subtle for HMAC on Browser WASM (#70745) * Use crypto.subtle for HMAC on Browser WASM Implement the browser "native" portion for HMAC on Browser WASM. I also made a few refactoring / simplifications where necessary. Contributes to #40074 * Add CreateChained rate limiter API (#70739) * [Mono] Fix C4018 warnings round II (#70783) * Fix C4018 warnings round II * Changes for x86 * Fix more C4018 warnings * Last set of files being fixed within this PR * Address review feedback and fix a build failure * Update upd_locator_t to be in sync with locator_t * Enabled tests that were reported to fail but now pass. (#71077) * [wasm][aot] Enable `DataContractSerializerTests.DCS_DerivedTypeWithDifferentOverrides` (#71083) * Align arm64 data section as requested (#71044) * Align arm64 data section as requested Currently, the data section alignment request is ignored unless it is 8. Since the minimum is 4, this effectively means that 16-byte SIMD16 data alignment requests are ignored. This is likely because this code was written before arm64 supported SIMD, and was never revised. Cases of SIMD loads of constant data lead to larger alignment padding of the data section. This is somewhat mitigated by https://github.com/dotnet/runtime/pull/71043 which fixes a bug with overallocation and overalignment of SIMD8 data loads. * Additional fixes 1. On arm64/LA64, if asking for a data alignment greater than code alignment, we need to increase the requested code alignment since the code section is where this data will live. This isn't viewable in SPMI diffs, but it does increase the alignment of some functions from 8 to 16 byte code alignment. 2. Assert that the data section is at least 4 bytes aligned (this is the default in our code, and alignment only increases). 3. Simplify the code setting the alignment flags for allocMem. * Formatting + disable alignment asserts It looks like the buffer pointer passed back from crossgen2 doesn't meet the alignment request. Perhaps it does in the final image, but not in the buffer the JIT fills in? Maybe the asserts could be used for JIT-time but not AOT (when the buffer address is the final location of the code/data)? * [mono] Extend MonoAOTCompiler Task (#70851) * [mono] Extend HelloWorld sample to use MonoAotCompiler Task * [mono] Extend MonoAotCompiler Task to invoke dotnet-pgo * Use cache for incremental builds * Remove SString::UIndex and SString::UIterator as they are never used. (#71103) * Add idIsBound() check in emitDispJumpList() (#71086) * Add idIsBound() check in emitDispJumpList() * Simpler code * Include all dlerror messages to DllNotFoundException (#70964) * [HTTP/3] Try catch for unreachable host in AltSvc H/3 upgrade test (#70993) * Try catch for unreachable host in AltSvc upgrade test * Fix after merge with main * Also skip HostUnreachable * Also skip ConnectionRefused * [main] Update dependencies from dotnet/linker (#70614) * Update dependencies from https://github.com/dotnet/linker build 20220610.2 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22310.2 * Update dependencies from https://github.com/dotnet/linker build 20220613.4 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22313.4 * Update dependencies from https://github.com/dotnet/linker build 20220614.2 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22314.2 * Update dependencies from https://github.com/dotnet/linker build 20220615.2 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22315.2 * Update dependencies from https://github.com/dotnet/linker build 20220616.2 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22316.2 * Update dependencies from https://github.com/dotnet/linker build 20220620.3 Microsoft.NET.ILLink.Tasks From Version 7.0.100-1.22308.1 -> To Version 7.0.100-1.22320.3 Co-authored-by: dotnet-maestro[bot] * [mono] Fix SpanHelpers.Reverse regression (#70650) * [mono] Fix SpanHelpers.Reverse regression SpanHelpers.Reverse was optimized recently using vectorized operations. However, the slow path (which is used by wasm for example) became slower. This change uses the old code pattern to reverse the array in non-vectorized scenario (or the rest of the array in the vectorized scenario). This is 2-3 times faster on wasm for example. * Mark method for inlining * Add check for minimum length This method can now be called with length 0 * Mark simple.il and nested.il ilasm/ildasm roundtrip incompatible (#71048) ildasm does not support precisely disassembling field RVAs. Fix #70876 * Make GC Stress 4/8 work with CET (#71085) * Make GC Stress 4/8 work with CET This change makes the GC stress 4/8 work without redirection. It also fixes a problem with missing unwinding of the shadow stack pointer that was not discovered before. I've found it while testing this change - it has manifested itself as a shadow stack overflow. And there is one more fix. The VSD Resolve stub was problematic to unwind through when null reference was passed as this to it. The stub had a push rdx as the first instruction and the dereference of this happened after that. So in case of the null, the call stack in the vectored exception handler contained a phantom frame caused by a problem unwinding from the stub. That caused incorrect updating of the shadow SP. I've fixed it by moving the dereference before the push. * Base64 library tests: use full encoding map (#71006) * [main] Update dependencies from dotnet/xharness (#71051) Co-authored-by: dotnet-maestro[bot] * Delete duplicate helper in HttpConnection.cs (#71091) * Use SequenceEqual in SslCredKey.Equals (#71097) * Simplify and improve SocketAddress.Equals (#71090) Use SequenceEqual rather than an open-coded loop. * Enable `TYP_STRUCT` `LCL_VAR/LCL_FLD` call args on x86 (#70779) * Enable local struct args on x86 * Delete SegmentCommandLine from utilcode (#71111) * Delete the Unix x64 implicit byref quirk (#70961) * Sort ConstrainedDirectCall cells (#71121) When a generic dictionary has multiple constrained calls, we would crash the compiler. I hit this in tests for #67745 but I want to separate this from the fix because that one is going to be quite a bit of code. * Allow guessing canonical owning type instantiations (#71120) This essentially undoes dotnet/runtimelab#958. I think the underlying problem no longer exists because we now run generic virtual method analysis on top of canonical bodies. * Fix test failure in Apple OSs due to paths too long and using Ustar which does not support long paths. (#71115) Co-authored-by: carlossanlop * Reduce allocations parsing X.509 certificates on Windows * Implement Tar Global Extended Attributes API changes (#70869) * ref: Global Extended Attributes API changes * src: Global Extended Attributes API changes * tests: Verify Global Extended Attributes API changes * Address suggestions * Address debug suggestion. * Improve the decision of reducing the size of the GEA path. * Use Path.GetTempPath for the GEA path. * Rename field tracking GEA entry number. Co-authored-by: carlossanlop * Normalize Watson crash buckets between .NET Core/.NET Framework (#71107) The Watson crash bucket code gets the program app name and if greater than 32 characters is hashed and written as based 64 encoded string. This has been done ever since .NET Framework. There was a bug introduced in .NET Core when the long file name support has added that changed the GetCurrentModuleFileName util function from getting just the module name without the path on Framework to returning the full path name. This caused the app name to always be hashed and encoded as hex bytes. The fix was to parse off the path and just use the module name. Issue: https://github.com/dotnet/runtime/issues/61580 * [mono][debugger] Support new hot reload features from runtime (#70697) * Support new hotreload features on mobile devices. * Implementing support to add methods in hotreload on mobile devices * Only invalidate code when we really have some change. * Remove printf * add/remove extra lines in eof * Sharing string between the debugger and the managed get capabilities API * Bump Newtonsoft.Json in /src/installer/tests/TestUtils (#71142) Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 9.0.1 to 13.0.1. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/9.0.1...13.0.1) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Print LARGEJMP instruction on ARM64 (#71094) emitter::emitDispIns supports printing LARGEJMP pseudo-instructions on ARM32, but not on ARM64. This method has been re-architected on ARM64 to support printing LARGEJMP instructions on ARM64. * Avoid delegate allocation in TraceSourceLoggerProvider.GetOrAddTraceSource (#71134) Every call to GetOrAddTraceSource was allocating a new delegate instance. * JSON contract customization (#70435) * Initial implementation for contract customization fix build errors Move converter rooting to DefaultJsonTypeInfoResolver so that it can be used standalone Fix ConfigurationList.IsReadOnly Minor refactorings (#1) * Makes the following changes: * Move singleton initialization for DefaultTypeInfoResolver behind a static property. * Consolidate JsonSerializerContext & IJsonTypeInfoResolver values to a single field. * Move reflection fallback logic away from JsonSerializerContext and into JsonSerializerOptions * Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs * remove testing of removed field Simplify the JsonTypeInfo.CreateObject implemenetation (#2) * Simplify the JsonTypeInfo.CreateObject implemenetation * Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs * Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.cs Co-authored-by: Krzysztof Wicher Co-authored-by: Krzysztof Wicher Tests and fixes for JsonTypeInfoKind.None TypeInfo type mismatch tests Allow setting NumberHandling on JsonTypeInfoKind.None test resolver returning wrong type of options JsonTypeInfo/JsonPropertyInfo mutability tests rename test file Move default converter rooting responsibility behind DefaultJsonTypeInfoResolver (#3) * Move default converter rooting responsibility behind DefaultJsonTypeInfoResolver * address feedback Add simple test for using JsonTypeInfo with APIs directly taking it fix and tests for untyped/typed CreateObject uncomment test cases, remove todo More tests and tiny fixes Add a JsonTypeInfoResolver.Combine test for JsonSerializerContext (#4) * Fix JsonTypeInfoResolver.Combine for JsonSerializerContext * Break up failing test Fix simple scenarios for combining contexts (#6) * Fix simple scenarios for combining contexts * feedback JsonSerializerContext combine test with different camel casing Remove unneeded virtual calls & branching when accessing Get & Set delegates (#7) JsonPropertyInfo tests everything minus ShouldSerialize & NumberHandling Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs Update src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs throw InvalidOperationException rather than ArgumentNullException for source gen when PropertyInfo.Name is assigned through JsonPropertyInfoValues tests for duplicated property names and JsonPropertyInfo.NumberHandling Add tests for NumberHandling and failing tests for ShouldSerialize disable the failing test and add extra checks disable remainder of the failing ShouldSerialize tests, fix working one Fix ShouldSerialize and IgnoreCondition interop Add failing tests for CreateObject + parametrized constructors Fix CreateObject support for JsonConstructor types (#10) * Fix CreateObject support for JsonConstructor types * address feedback Make contexts more combinator friendly (#9) * Make contexts more combinator friendly * remove converter cache * redesign test to account for JsonConstructorAttribute * Combine unit tests * address feedback * Add acceptance tests for DataContract attributes & Specified pattern (#11) * Add private field serialization acceptance test (#13) * tests, PR feedback (#14) * PR feedback and extra tests * Shorten class name, remove incorrect check (not true for polimorphic cases) * Make parameter matching for custom properties map property Name with parameter (#16) * Test static initialization with JsonTypeInfo (#17) * Fix test failures and proper fix this time (#18) * Fix test failures and proper fix this time * reinstate ActiveIssueAttribute * PR feedback and adjust couple of tests which don't set TypeInfoResolver * fix IAsyncEnumerable tests * Lock JsonSerializerOptions in JsonTypeInfo.EnsureConfigured() Co-authored-by: Eirik Tsarpalis Co-authored-by: Eirik Tsarpalis * JIT: Stop reordering arguments throwing distinct exceptions (#70893) Implement a precise scan for arguments that may throw exceptions which collects the exceptions they may throw. When we see two such interfering sets, make sure that the first argument is evaluated to a temp so that they do not get reordered by the later sort. Fix #63905 * VM: Better strategy for TryReserveInitialMemory on arm64 (jump stubs) (#70707) * Better strategy for ReserveInitialMemory on arm64 * Clean up * Address feedback * fix "below" case * Address feedback * Update virtual.cpp * Apply suggestions from code review Co-authored-by: Jan Vorlicek * Address feedback * Fix defines * Remove env var * clean up * Clean up * Update virtual.h Co-authored-by: Jan Vorlicek * Add exception interop test for validating native exception interop on Windows + CoreCLR. (#70110) * Fix ILGenerator maxstack computation (#70388) * Fix ILGenerator maxstack computation When generating a dynamic method both with many unconditional jumps, the ILGenerator's computation of maxstack is way to large - it adds the max stack of each basic block ending with an unconditional transfer (br, ret, throw, etc). If the generated code has many such bbs (eg, from the "then" clauses of if-then-else constructs) this sum can overflow 2^16. When it does, the maxstack recorded/used is the computed value mod 2^16. When that is less than the correct value, the JIT throws an InvalidProgramException. Keep track of the stack depth at various positions and use it to calculate an adjustment to the depth. Fix #63805 * Fix System.Linq.Expressions tests * Remove stack handling in MethodBuilder * Enable fake hot/cold splitting on ARM64 (#70708) This commit contains fixes for various bugs exposed by enabling fake hot/cold splitting on ARM64: - Branches between hot/cold sections are now always long. - The pseudoinstruction for loading a constant from the cold section did not support loading 16-byte data into vector registers, as it temporarily loaded the constant into an 8-byte integer register. Now, 16-byte constants are loaded directly into vector registers via an `ld1` instruction. - Asserts/NYIs blocking hot/cold splitting on ARM64 have been removed. Fake hot/cold splitting requires we fake unwind info by treating each split function as one hot section. A more architecture-agnostic approach for this has been applied. To facilitate this approach, the fake-splitting implementation has been revised to place the hot and cold sections contiguously in memory (immediately followed by the read-only data section on ARM64). * Simplify NtProcessInfoHelper.GetProcessShortName (#71136) The previous code was iterating character by character through the name, looking for the last occurrence of a slash and the last occurrence of a period. For the slash, we can just LasIndexOfAny. For the period, it was only doing this in order to trim off ".exe" if a period was found and the text at that point was ".exe"... so we can just compare the end with ".exe". * Exposing AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi for ITrigonometricFunctions (#71033) * Exposing AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi for ITrigonometricFunctions * Adding tests for AcosPi, AsinPi, Atan2Pi, AtanPi, CosPi, SinPi, and TanPi * Fixing the handling of AcosPi, AsinPi, and AtanPi tests on WASM/Unix * Add tests for `IMallocSpy` (#71106) * Add tests for IMallocSpy * Work around for UriFormatException caused by \\?\ prefix in the path (#71082) * Make RateLimitPartition.Factory public (#71145) * Make RateLimitPartition.Factory public * Fix tests * Fix comment * Bump Newtonsoft.Json from 9.0.1 to 13.0.1 in /src/tests/ilverify (#71141) Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 9.0.1 to 13.0.1. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/9.0.1...13.0.1) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [iOS][Android] Fix crash in Exception.CaptureDispatchState (#70970) There is a crash in `Exception.CaptureDispatchState` when called from one thread at the same time another calls into `Exception.RestoreDispatchState`. The reason for the crash is due to the way we do not update `foreignExceptionFrames` in a thread-safe way. `foreignExceptionFrames` is used in both methods and can crash when the size changes before the array is copied. The fix copies `foreignExceptionFrame` into a local variable in `CaptureDispatchState` Fixes https://github.com/dotnet/runtime/issues/70081 * Fix the heuristics for L3 cache size for Arm64 (#71029) * Get cacheLevel for unix * Get cacheLevel for windows * Get cacheLevel for os * add the macro CHECK_CACHE_SIZE * fix multiplier * Review comments * Fix linux arm64 build * Change from std:string to char[] * minor nit * opps should be outside the loop * Replace assert with _ASSERTE * CHECK_CACHE_SIZE -> UPDATE_CACHE_SIZE_AND_LEVEL * Use GetTotalProcessorCount for windows * Fix the handling of UInt128.DivideSlow on big endian platforms (#71162) * Fix Native Digits Support (#71045) * [LibraryImportGenerator] Basic stateless value marshaller support (#71116) - Separate out previous custom marshalling support into _V1 classes - Add basic support for new stateless marshaller shape for values This only adds really basic support for stateless value marshalling. It doesn't deal with support for caller-allocated buffer, pinning, guaranteed unmarshal, or linear collection marshalling. * NextObj fix (#71113) this is to fix #70231. for regions we could run into this situation - object is the last object before heap_segment_allocated (hs) T0 calls NextObj, gets next obj which starts at heap_segment_allocated (hs) T1 changes ephemeral_heap_segment to hs T0 does these comparisons (nextobj >= heap_segment_allocated(hs) && hs != hp->ephemeral_heap_segment) || (nextobj >= hp->alloc_allocated)) both still false because alloc_allocated hasn't been changed just yet (and the old alloc_allocated is larger than nextobj) T0 validates next obj, concludes its m_alignpad is not 0, asserts T1 forms an allocation context starting at heap_segment_allocated, clears memory so by the time the dump is taken, m_alignpad is already cleared (actually we clear it in a_fit_segment_end) I'm fixing this by saving the ephemeral_heap_segment and alloc_allocated and bail if nextobj is not on the saved eph seg or if those 2 saved values are no long in sync. * Fix for issue 70385 (stack overflow in the CoreCLR runtime during SVM validation) (#71135) * Regression test for recursive generics causing runtime stack overflow * Adjust load levels in SVM validation to prevent infinite recursion * Fix C# source code per hez2010's PR feedback * Address David's PR feedback * Fix TryResolveVirtualStaticMethodOnThisType per David's feedback * Fix Tar timestamp conversion from/to string and DateTimeOffset (#71038) * Change double to decimal in timestamp conversions to preserve precision * Re-enable disabled test * Adjust assert message * Reuse FileSystemInfo Last*TimeUtc fields, use implicit cast operator to store as DateTimeOffset. * Fix using wrong fieldname for ctime. * Using 'G' for decimal to string conversion. Adjust test to not require a dot. The DateTimeOffset comparison done afterwards should suffice. * Ensure timestamps are converted to long, not int. * Add Epochalypse and Past-octal-limit timestamp tests * TarHelpers methods can be private * Remove unreachable code for adding ctime and atime before writing Pax entry. Add tests to ensure we always add those entries to the dictionary on construction. * Fix typo in test when retrieving ctime. * Make sure CTime adds nanoseconds on Unix when retrieving info from disk. Co-authored-by: carlossanlop * Use IndexOfAny in HttpListener.HandleAuthentication (#71137) * Use IndexOfAny in HttpListener.HandleAuthentication Just cleaning up a manual loop that can instead be IndexOfAny. * Fix missing check * Change SString::GetUTF8NoConvert to GetUTF8 that converts the SString (#71101) * Change SString::GetUTF8NoConvert to GetUTF8 that converts the SString This enables SString to get out of the UTF16 state and helps move us away from "SString's natural encoding is UTF16" * Remove some stack scratch buffers that are unneeded now (as we can now convert the SString itself and in some cases it was already in UTF8) and implement PR feedback. * Add SetAndConvertToUTF8 method and remove the GetUTF8 method variants with a scratch buffer. * Remove unneeded variables. Co-authored-by: Jan Kotas Co-authored-by: Aaron Robinson Co-authored-by: Jan Kotas * JIT: arm64 osr funclet frame probing (#70916) We currently need to pad OSR funclet frames with the full size of the Tier0 frame, and this paddign sits above the register save area. For large Tier0 frames we thus need to probe the stack in the OSR prolog for type 1, 3, and 5 frames, before doing the initial SP adjustment and save. Longer term the plan is to revise arm64 OSR so we will not need to do this padding; at that point we can remove this extra probing. Fixes #70263. * Mirror Microsoft.Diagnostics.NETCore.Client (#71139) Microsoft.Diagnostics.NETCore.Client change to allow future branches to build correctly in runtimelab * Update design docs to reflect our new marshaller design from partner feedback (#71017) Co-authored-by: Aaron Robinson Co-authored-by: Elinor Fung * Implement UnixFileMode APIs (#69980) * Implement UnixFileMode APIs on Unix. * Throw PNSE on Windows, add UnsupportedOSPlatform. * Fix API compat issue. * Borrow a few things from SafeFileHandle API PR to this compiles. * Fix System.IO.FileSystem.AccessControl compilation. * Add xml docs. * Replace Interop.Sys.Permissions to System.IO.UnixFileMode. * Throw PNSE immediately on Windows. * Add ODE to xml docs of methods that accept a handle. * Don't throw (PNSE) from FileSystemInfo.UnixFileMode getter on Windows. * Minor style fix. * Get rid of some casts. Co-authored-by: Eric Erhardt * Add tests for creating a file/directory with UnixFileMode. * Some CI envs don't have a umask exe, try retrieving via a shell builtin. * Update expected test mode values. * Fix OSX * Fix Windows build. * Add ArgumentException tests. * Fix Windows build. * Add get/set tests. * Update test for Windows. * Make setters target link instead of link target. * Linux: fix SetUnixFileMode * Fix OSX compilation. * Try make all tests pass in CI. * For link, operate on target permissions. * Skip tests on Browser. * Add tests for 'Get' that doesn't use a 'Set' first. * Don't perform exist check for handles. * Fix Get test for wasm. * Review xml comments. * Add comment to test. * GetUnixFileMode for handle won't throw UnauthorizedAccessException. * Apply suggestions from code review Co-authored-by: Eric Erhardt * PR feedback. * Update enum doc to say 'owner' instead of 'user'. * Use UnixFileMode in library. * Use UnixFileMode in library tests. * Fix Windows build. * Fix missing FileAccess when changing to FileStreamOptions API. * PR feedback. * Fix Argument_InvalidUnixCreateMode message. Co-authored-by: Adam Sitnik Co-authored-by: Eric Erhardt Co-authored-by: Adam Sitnik * Update apphost error dialog text to put question last (#71165) * [NativeAOT] Enable dynamic linking of ucrt for release runtime (#71182) This is enabled for release runtime only, same as how we do it for regular CoreCLR builds. * Fix Unix test failures. Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> Co-authored-by: Ankit Jain Co-authored-by: Jakob Botsch Nielsen Co-authored-by: Levi Broderick Co-authored-by: Kevin Jones Co-authored-by: Mike McLaughlin Co-authored-by: Elinor Fung Co-authored-by: Rolf Bjarne Kvinge Co-authored-by: Filip Navara Co-authored-by: Stephen Toub Co-authored-by: Kunal Pathak Co-authored-by: Huo Yaoyuan Co-authored-by: Dan Moseley Co-authored-by: Aaron Robinson Co-authored-by: Brennan Co-authored-by: Dennis Yemelyanov <10681271+dennis-yemelyanov@users.noreply.github.com> Co-authored-by: Aleksey Kliger (λgeek) Co-authored-by: Gleb Balykov Co-authored-by: Thays Grazia Co-authored-by: Andy Gocke Co-authored-by: Badre BSAILA <54767641+pedrobsaila@users.noreply.github.com> Co-authored-by: Buyaa Namnan Co-authored-by: Egor Bogatov Co-authored-by: Tomáš Rylek Co-authored-by: Tomas Weinfurt Co-authored-by: Jan Kotas Co-authored-by: Vladimir Sadov Co-authored-by: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Co-authored-by: Tanner Gooding Co-authored-by: Andrii Kurdiumov Co-authored-by: Michal Strehovský Co-authored-by: Fan Yang <52458914+fanyang-mono@users.noreply.github.com> Co-authored-by: Jan Vorlicek Co-authored-by: Andy Ayers Co-authored-by: Jeremy Barton Co-authored-by: Andrew Au Co-authored-by: Juan Hoyos Co-authored-by: Noah Falk Co-authored-by: Tlakaelel Axayakatl Ceja Co-authored-by: Jan Vorlicek Co-authored-by: Lakshan Fernando Co-authored-by: Aman Khalid Co-authored-by: Jeremy Koritzinsky Co-authored-by: Theodore Tsirpanis Co-authored-by: Will Smith Co-authored-by: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Co-authored-by: Carlos Sanchez <1175054+carlossanlop@users.noreply.github.com> Co-authored-by: Buyaa Namnan Co-authored-by: Joni Aromaa Co-authored-by: Katelyn Gadd Co-authored-by: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Co-authored-by: Eric Erhardt Co-authored-by: carlossanlop Co-authored-by: Mikhail Kurinnoi Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: dotnet-maestro[bot] Co-authored-by: Alexander Köplinger Co-authored-by: Larry Ewing Co-authored-by: Bruce Forstall Co-authored-by: Sychev Vadim Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> Co-authored-by: Steve Dunn Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> Co-authored-by: Vikas Gupta <93921236+vikasgupta8@users.noreply.github.com> Co-authored-by: Alhad Deshpande Co-authored-by: Youssef Victor Co-authored-by: Maryam Ariyan Co-authored-by: David Wrighton Co-authored-by: Alan Hayward Co-authored-by: Stephen Halter Co-authored-by: Martin Costello Co-authored-by: Jeff Handley Co-authored-by: David Cantú Co-authored-by: Gregory Bell <65985703+grbell-ms@users.noreply.github.com> Co-authored-by: Eirik Tsarpalis Co-authored-by: Steve Pfister Co-authored-by: Tarek Mahmoud Sayed Co-authored-by: MSDN.WhiteKnight <35516665+MSDN-WhiteKnight@users.noreply.github.com> Co-authored-by: Anton Firszov Co-authored-by: Ivan Povazan <55002338+ivanpovazan@users.noreply.github.com> Co-authored-by: Jérôme Laban Co-authored-by: Marek Fišera Co-authored-by: Mitchell Hwang <16830051+mdh1418@users.noreply.github.com> Co-authored-by: Hyungju Lee Co-authored-by: Vlad Brezae Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Krzysztof Wicher Co-authored-by: panguye <105525993+panguye@users.noreply.github.com> Co-authored-by: William Godbe Co-authored-by: Maoni Stephens Co-authored-by: Tom Deseyn Co-authored-by: Adam Sitnik --- .config/dotnet-tools.json | 2 +- Directory.Build.props | 1 + THIRD-PARTY-NOTICES.TXT | 37 + docs/coding-guidelines/clr-code-guide.md | 2 +- docs/coding-guidelines/mono-code-guide.md | 253 ++ docs/design/coreclr/botr/dac-notes.md | 2 +- .../LibraryImportGenerator/Compatibility.md | 9 + .../LibraryImportGenerator/Pipeline.md | 12 +- .../LibraryImportGenerator/SpanMarshallers.md | 2 + .../StructMarshalling.md | 4 +- .../UserTypeMarshallingV2.md | 768 ++++ docs/design/security/unix-tmp.md | 45 + docs/design/specs/Ecma-335-Augments.md | 5 + docs/project/dogfooding.md | 15 +- eng/CodeAnalysis.src.globalconfig | 29 +- eng/CodeAnalysis.test.globalconfig | 3 + eng/Subsets.props | 4 +- eng/Version.Details.xml | 184 +- eng/Versions.props | 86 +- eng/build.sh | 6 +- eng/common/init-tools-native.ps1 | 11 +- eng/common/native/init-compiler.sh | 2 +- eng/common/tools.ps1 | 4 + eng/native/build-commons.sh | 6 +- eng/native/configurecompiler.cmake | 10 + eng/native/configureplatform.cmake | 9 + eng/native/configuretools.cmake | 2 +- eng/native/functions.cmake | 4 + eng/native/init-os-and-arch.sh | 3 + eng/native/tryrun.cmake | 6 +- .../templates/runtimes/run-test-job.yml | 9 +- .../templates/wasm-library-aot-tests.yml | 2 + .../common/templates/wasm-library-tests.yml | 2 + eng/pipelines/coreclr/libraries-pgo.yml | 2 +- eng/pipelines/coreclr/templates/build-job.yml | 2 + eng/pipelines/libraries/run-test-job.yml | 3 +- .../runtime-extra-platforms-other.yml | 33 +- eng/pipelines/runtime-staging.yml | 2 + eng/pipelines/runtime.yml | 6 +- eng/testing/tests.props | 12 - eng/testing/tests.targets | 12 + eng/testing/tests.wasm.targets | 8 + eng/testing/xunit/xunit.console.targets | 5 + global.json | 12 +- ....PortableThreadPool.NativeSinks.CoreCLR.cs | 4 + .../src/System/Environment.CoreCLR.cs | 19 +- .../src/System/Exception.CoreCLR.cs | 27 + .../Reflection/Emit/DynamicILGenerator.cs | 2 +- .../src/System/Reflection/Emit/ILGenerator.cs | 156 +- .../System/Reflection/Emit/MethodBuilder.cs | 4 +- .../Reflection/MethodInvoker.CoreCLR.cs | 17 +- .../src/System/Reflection/RuntimeAssembly.cs | 5 +- .../Runtime/CompilerServices/CastHelpers.cs | 7 +- .../src/System/ValueType.cs | 2 +- src/coreclr/binder/assemblybindercommon.cpp | 3 +- src/coreclr/binder/customassemblybinder.cpp | 3 +- src/coreclr/binder/defaultassemblybinder.cpp | 3 +- .../binder/inc/assemblybindercommon.hpp | 1 + src/coreclr/binder/inc/customassemblybinder.h | 1 + .../binder/inc/defaultassemblybinder.h | 1 + src/coreclr/classlibnative/bcltype/system.cpp | 37 - src/coreclr/classlibnative/bcltype/system.h | 1 - src/coreclr/debug/daccess/daccess.cpp | 2 +- src/coreclr/debug/daccess/dacdbiimpl.cpp | 8 +- .../debug/daccess/ppc64le/primitives.cpp | 8 + src/coreclr/debug/daccess/request.cpp | 11 +- src/coreclr/debug/ee/debugger.cpp | 2 +- src/coreclr/debug/ee/debugger.h | 2 +- src/coreclr/debug/ee/functioninfo.cpp | 3 + src/coreclr/debug/ee/ppc64le/dbghelpers.S | 8 + src/coreclr/debug/ee/ppc64le/primitives.cpp | 9 + .../debug/shared/ppc64le/primitives.cpp | 15 + src/coreclr/dlls/mscorrc/mscorrc.rc | 1 - src/coreclr/dlls/mscorrc/resource.h | 1 - src/coreclr/gc/env/etmdummy.h | 1 + src/coreclr/gc/env/gcenv.os.h | 11 - src/coreclr/gc/gc.cpp | 22 +- src/coreclr/gc/unix/cgroup.cpp | 99 +- src/coreclr/gc/unix/gcenv.unix.cpp | 97 +- src/coreclr/gc/windows/gcenv.windows.cpp | 48 +- src/coreclr/ilasm/assembler.h | 4 - src/coreclr/ilasm/main.cpp | 4 - src/coreclr/ildasm/dasm.cpp | 1 - src/coreclr/ildasm/windasm.cpp | 91 +- src/coreclr/inc/contxt.h | 3471 ----------------- src/coreclr/inc/corhlprpriv.h | 4 +- src/coreclr/inc/corinfo.h | 21 +- src/coreclr/inc/corjit.h | 21 +- src/coreclr/inc/crosscomp.h | 2 + src/coreclr/inc/defaultallocator.h | 48 - src/coreclr/inc/iallocator.h | 44 - src/coreclr/inc/icorjitinfoimpl_generated.h | 4 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/inc/jithelpers.h | 7 +- src/coreclr/inc/llvm/ELF.h | 4 +- src/coreclr/inc/pedecoder.h | 2 + src/coreclr/inc/readytorun.h | 2 +- src/coreclr/inc/regex_base.h | 972 ----- src/coreclr/inc/regex_util.h | 208 - src/coreclr/inc/sstring.h | 66 +- src/coreclr/inc/sstring.inl | 125 +- src/coreclr/inc/static_assert.h | 6 - src/coreclr/inc/switches.h | 2 +- src/coreclr/inc/utilcode.h | 34 - src/coreclr/inc/volatile.h | 4 +- src/coreclr/jit/CMakeLists.txt | 18 +- src/coreclr/jit/ClrJit.PAL.exports | 1 + src/coreclr/jit/ClrJit.exports | 1 + src/coreclr/jit/ICorJitInfo_API_names.h | 1 + src/coreclr/jit/ICorJitInfo_API_wrapper.hpp | 9 + src/coreclr/jit/assertionprop.cpp | 92 +- src/coreclr/jit/block.h | 52 +- src/coreclr/jit/codegen.h | 9 +- src/coreclr/jit/codegenarm64.cpp | 165 +- src/coreclr/jit/codegenarmarch.cpp | 259 +- src/coreclr/jit/codegencommon.cpp | 30 +- src/coreclr/jit/codegenlinear.cpp | 68 +- src/coreclr/jit/codegenloongarch64.cpp | 12 + src/coreclr/jit/codegenxarch.cpp | 226 +- src/coreclr/jit/compiler.cpp | 44 +- src/coreclr/jit/compiler.h | 169 +- src/coreclr/jit/compiler.hpp | 26 +- src/coreclr/jit/decomposelongs.cpp | 3 - src/coreclr/jit/ee_il_dll.cpp | 62 +- src/coreclr/jit/emit.cpp | 194 +- src/coreclr/jit/emit.h | 8 +- src/coreclr/jit/emitarm.cpp | 104 +- src/coreclr/jit/emitarm.h | 8 + src/coreclr/jit/emitarm64.cpp | 454 ++- src/coreclr/jit/emitarm64.h | 18 +- src/coreclr/jit/emitloongarch64.cpp | 2 +- src/coreclr/jit/emitloongarch64.h | 6 + src/coreclr/jit/emitxarch.cpp | 29 +- src/coreclr/jit/emitxarch.h | 5 +- src/coreclr/jit/fgbasic.cpp | 2 +- src/coreclr/jit/fginline.cpp | 3 +- src/coreclr/jit/fgopt.cpp | 7 +- src/coreclr/jit/fgprofile.cpp | 321 +- src/coreclr/jit/flowgraph.cpp | 44 +- src/coreclr/jit/forwardsub.cpp | 40 +- src/coreclr/jit/gentree.cpp | 433 +- src/coreclr/jit/gentree.h | 175 +- src/coreclr/jit/gtlist.h | 1 + src/coreclr/jit/hwintrinsic.cpp | 70 +- src/coreclr/jit/importer.cpp | 745 ++-- src/coreclr/jit/indirectcalltransformer.cpp | 302 +- src/coreclr/jit/inline.cpp | 35 +- src/coreclr/jit/inline.h | 52 +- src/coreclr/jit/instrsxarch.h | 4 +- src/coreclr/jit/jit.h | 23 +- src/coreclr/jit/jitconfigvalues.h | 10 +- src/coreclr/jit/lclmorph.cpp | 72 +- src/coreclr/jit/lclvars.cpp | 161 +- src/coreclr/jit/likelyclass.cpp | 257 +- src/coreclr/jit/loopcloning.cpp | 19 + src/coreclr/jit/lower.cpp | 213 +- src/coreclr/jit/lower.h | 3 +- src/coreclr/jit/lowerarmarch.cpp | 145 +- src/coreclr/jit/lowerloongarch64.cpp | 24 + src/coreclr/jit/lowerxarch.cpp | 202 +- src/coreclr/jit/lsraarmarch.cpp | 51 +- src/coreclr/jit/lsraxarch.cpp | 24 +- src/coreclr/jit/morph.cpp | 1398 +++---- src/coreclr/jit/optcse.cpp | 33 +- src/coreclr/jit/optimizer.cpp | 678 +++- src/coreclr/jit/patchpoint.cpp | 2 +- src/coreclr/jit/rangecheck.cpp | 81 +- src/coreclr/jit/rangecheck.h | 127 +- src/coreclr/jit/rationalize.cpp | 99 +- src/coreclr/jit/rationalize.h | 4 + src/coreclr/jit/scopeinfo.cpp | 4 +- src/coreclr/jit/simd.cpp | 61 +- src/coreclr/jit/targetamd64.h | 2 + src/coreclr/jit/targetarm.h | 1 + src/coreclr/jit/targetarm64.h | 1 + src/coreclr/jit/targetloongarch64.h | 1 + src/coreclr/jit/targetx86.h | 1 + src/coreclr/jit/unwind.cpp | 18 +- src/coreclr/jit/unwindamd64.cpp | 67 +- src/coreclr/jit/unwindarm.cpp | 45 +- src/coreclr/jit/unwindx86.cpp | 63 +- src/coreclr/jit/valuenum.cpp | 302 +- src/coreclr/jit/valuenum.h | 7 +- src/coreclr/minipal/Unix/doublemapping.cpp | 21 + .../BuildIntegration/BuildIntegration.proj | 5 + .../Microsoft.NETCore.Native.Unix.props | 1 - .../Microsoft.NETCore.Native.Windows.props | 6 + .../Microsoft.NETCore.Native.targets | 11 +- .../src/Internal/Runtime/MethodTable.cs | 8 +- .../DeveloperExperienceModeOnlyAttribute.cs | 46 - .../DeveloperExperienceState.cs | 1 - src/coreclr/nativeaot/Directory.Build.props | 2 +- .../src/System/Runtime/RuntimeExports.cs | 2 +- .../src/System/Runtime/ThunkPool.cs | 2 +- src/coreclr/nativeaot/Runtime/CMakeLists.txt | 5 +- src/coreclr/nativeaot/Runtime/startup.cpp | 57 + .../nativeaot/Runtime/unix/PalRedhawkUnix.cpp | 9 +- .../Runtime/windows/CoffNativeCodeManager.cpp | 61 +- .../src/ILLink/ILLink.Substitutions.xml | 3 + .../DeveloperExperience.cs | 2 +- .../Reflection/Core/AssemblyBinder.cs | 5 + .../Core/Execution/ExecutionDomain.cs | 17 +- .../Core/Execution/ExecutionEnvironment.cs | 3 + .../Core/Execution/FieldAccessor.cs | 3 + .../Core/Execution/MethodInvoker.cs | 8 +- .../Core/Execution/ReflectionCoreExecution.cs | 3 + .../Reflection/Core/ReflectionDomainSetup.cs | 7 +- .../Runtime/Augments/TypeLoaderCallbacks.cs | 5 + .../Runtime/CompilerHelpers/InteropHelpers.cs | 2 +- .../src/System.Private.CoreLib.csproj | 149 +- .../src/System/ActivatorImplementation.cs | 10 +- .../src/System/Array.NativeAot.cs | 2 +- .../src/System/Environment.NativeAot.cs | 7 + .../src/System/Helpers.cs | 27 - .../src/System/MulticastDelegate.cs | 4 +- .../src/System/Reflection/Emit/ILGenerator.cs | 2 +- ...imeAssembly.GetTypeCore.CaseInsensitive.cs | 2 +- ...ntimeAssembly.GetTypeCore.CaseSensitive.cs | 0 .../NativeFormatRuntimeAssembly.cs | 4 +- .../Runtime/Assemblies/RuntimeAssemblyInfo.cs | 12 +- .../BindingFlagSupport/ConstructorPolicies.cs | 4 +- .../BindingFlagSupport/EventPolicies.cs | 28 +- .../BindingFlagSupport/FieldPolicies.cs | 2 +- .../BindingFlagSupport/MemberPolicies.cs | 2 +- .../BindingFlagSupport/MemberTypeIndex.cs | 0 .../BindingFlagSupport/MethodPolicies.cs | 6 +- .../NameFilter.NativeFormat.cs | 0 .../Runtime/BindingFlagSupport/NameFilter.cs | 0 .../BindingFlagSupport/NestedTypePolicies.cs | 2 +- .../BindingFlagSupport/PropertyPolicies.cs | 18 +- .../BindingFlagSupport/QueriedMemberList.cs | 2 +- .../QueryResult.Enumerator.cs | 0 .../Runtime/BindingFlagSupport/QueryResult.cs | 4 +- .../Runtime/BindingFlagSupport/Shared.cs | 4 +- .../NativeFormatCustomAttributeData.cs | 18 +- .../RuntimeCustomAttributeData.cs | 10 +- .../RuntimePseudoCustomAttributeData.cs | 0 .../Dispensers/DefaultDispenserPolicy.cs | 0 .../Runtime/Dispensers/Dispenser.cs | 0 .../Runtime/Dispensers/DispenserAlgorithm.cs | 0 .../Runtime/Dispensers/DispenserFactory.cs | 0 .../Runtime/Dispensers/DispenserPolicy.cs | 0 .../Runtime/Dispensers/DispenserScenario.cs | 0 .../Dispensers/DispenserThatAlwaysCreates.cs | 0 .../Dispensers/DispenserThatAlwaysReuses.cs | 0 .../DispenserThatReusesAsLongAsKeyIsAlive.cs | 0 ...nserThatReusesAsLongAsKeyedValueIsAlive.cs | 0 ...DispenserThatReusesAsLongAsValueIsAlive.cs | 0 .../NativeFormatRuntimeEventInfo.cs | 0 .../Runtime/EventInfos/RuntimeEventInfo.cs | 0 .../NativeFormatRuntimeFieldInfo.cs | 6 +- .../Runtime/FieldInfos/RuntimeFieldInfo.cs | 0 .../Runtime/General/Assignability.cs | 18 +- .../BlockedRuntimeTypeNameGenerator.cs | 0 .../General/Dispensers.NativeFormat.cs | 2 +- .../Reflection/Runtime/General/Dispensers.cs | 6 +- .../Runtime/General/Helpers.NativeFormat.cs | 0 .../Reflection/Runtime/General/Helpers.cs | 12 +- ...ntimeMemberInfoWithNoMetadataDefinition.cs | 0 .../General/LegacyCustomAttributeApis.cs | 0 .../Reflection/Runtime/General/ListBuilder.cs | 0 .../MetadataReaderExtensions.NativeFormat.cs | 33 +- .../General}/MetadataReaderExtensions.cs | 11 +- .../Runtime/General/NamespaceChain.cs | 2 +- .../NativeFormat/DefaultValueParser.cs | 2 +- .../Runtime/General/QHandles.NativeFormat.cs | 1 - .../Reflection/Runtime/General/QHandles.cs | 13 + .../QSignatureTypeHandle.NativeFormat.cs | 0 .../Runtime/General/QSignatureTypeHandle.cs | 15 +- .../ReflectionCoreCallbacksImplementation.cs | 4 +- .../Runtime/General/RuntimeTypeHandleKey.cs | 0 .../Reflection/Runtime/General/ThunkedApis.cs | 9 +- .../Runtime/General/ToStringUtils.cs | 2 +- .../Reflection/Runtime/General/TypeContext.cs | 0 .../Runtime/General/TypeForwardInfo.cs | 0 .../General/TypeResolver.NativeFormat.cs | 30 +- .../Runtime/General/TypeResolver.cs | 6 +- .../General/TypeUnifier.NativeFormat.cs | 0 .../Reflection/Runtime/General/TypeUnifier.cs | 2 +- .../MethodInfos/CustomMethodInvoker.cs | 2 +- .../MethodInfos/CustomMethodInvokerAction.cs | 0 .../CustomMethodMapper.Nullable.cs | 3 +- .../MethodInfos/CustomMethodMapper.String.cs | 0 .../Runtime/MethodInfos/CustomMethodMapper.cs | 6 +- .../MethodInfos/IRuntimeMethodCommon.cs | 0 .../Runtime/MethodInfos/InvokerOptions.cs | 0 .../NativeFormat/NativeFormatMethodCommon.cs | 8 +- .../Runtime/MethodInfos/OpenMethodInvoker.cs | 2 +- .../RuntimeClsIdNullaryConstructorInfo.cs | 4 +- .../RuntimeConstructedGenericMethodInfo.cs | 2 +- .../MethodInfos/RuntimeConstructorInfo.cs | 8 +- .../MethodInfos/RuntimeDummyMethodInfo.cs | 2 +- .../MethodInfos/RuntimeMethodHelpers.cs | 2 +- .../Runtime/MethodInfos/RuntimeMethodInfo.cs | 6 +- .../MethodInfos/RuntimeNamedMethodInfo.cs | 6 +- .../RuntimePlainConstructorInfo.cs | 6 +- .../RuntimeSyntheticConstructorInfo.cs | 6 +- .../MethodInfos/RuntimeSyntheticMethodInfo.cs | 4 +- .../Runtime/MethodInfos/SyntheticMethodId.cs | 0 .../VirtualRuntimeParameterInfoArray.cs | 0 .../NativeFormat/NativeFormatRuntimeModule.cs | 0 .../Runtime/Modules/RuntimeModule.cs | 2 - .../NativeFormatMethodParameterInfo.cs | 2 +- .../RuntimeFatMethodParameterInfo.cs | 0 .../RuntimeMethodParameterInfo.cs | 0 .../ParameterInfos/RuntimeParameterInfo.cs | 0 .../RuntimePropertyIndexParameterInfo.cs | 0 .../RuntimeSyntheticParameterInfo.cs | 2 +- .../RuntimeThinMethodParameterInfo.cs | 2 +- .../EcmaFormatRuntimePropertyInfo.cs | 0 .../NativeFormatRuntimePropertyInfo.cs | 2 +- .../PropertyInfos/RuntimePropertyInfo.cs | 8 +- ...veFormatRuntimeGenericParameterTypeInfo.cs | 2 +- ...ameterTypeInfoForMethods.UnificationKey.cs | 0 ...ntimeGenericParameterTypeInfoForMethods.cs | 0 ...arameterTypeInfoForTypes.UnificationKey.cs | 0 ...RuntimeGenericParameterTypeInfoForTypes.cs | 0 ...rmatRuntimeNamedTypeInfo.UnificationKey.cs | 0 .../NativeFormatRuntimeNamedTypeInfo.cs | 10 +- ...veFormatRuntimeTypeInfo.CoreGetDeclared.cs | 0 .../Runtime/TypeInfos/RuntimeArrayTypeInfo.cs | 0 .../TypeInfos/RuntimeBlockedTypeInfo.cs | 4 +- .../Runtime/TypeInfos/RuntimeByRefTypeInfo.cs | 0 .../RuntimeClsIdTypeInfo.UnificationKey.cs | 0 .../Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs | 4 +- ...nstructedGenericTypeInfo.UnificationKey.cs | 0 .../RuntimeConstructedGenericTypeInfo.cs | 4 +- .../RuntimeGenericParameterTypeInfo.cs | 0 ...untimeHasElementTypeInfo.UnificationKey.cs | 0 .../TypeInfos/RuntimeHasElementTypeInfo.cs | 6 +- .../Runtime/TypeInfos/RuntimeNamedTypeInfo.cs | 10 +- .../RuntimeNoMetadataNamedTypeInfo.cs | 2 +- .../TypeInfos/RuntimePointerTypeInfo.cs | 0 .../RuntimeTypeDefinitionTypeInfo.cs | 0 .../TypeInfos/RuntimeTypeInfo.BindingFlags.cs | 0 .../RuntimeTypeInfo.CoreGetDeclared.cs | 10 +- .../TypeInfos/RuntimeTypeInfo.GetMember.cs | 19 +- .../TypeInfos/RuntimeTypeInfo.InvokeMember.cs | 49 +- .../RuntimeTypeInfo.TypeComponentsCache.cs | 0 .../Runtime/TypeInfos/RuntimeTypeInfo.cs | 30 +- .../Runtime/TypeParsing/GetTypeOptions.cs | 0 .../Runtime/TypeParsing/TypeLexer.cs | 0 .../Runtime/TypeParsing/TypeName.cs | 2 +- .../Runtime/TypeParsing/TypeParser.cs | 2 +- .../ClassConstructorRunner.cs | 2 +- .../NativeLibrary.NativeAot.Unix.cs | 9 +- .../src/System/Runtime/RuntimeImports.cs | 26 +- .../src/System/RuntimeTypeHandle.cs | 3 +- .../Win32ThreadPoolPreAllocatedOverlapped.cs | 2 +- .../src/System/Type.Internal.cs | 30 +- .../Internal/Reflection/RuntimeTypeInfo.cs | 30 + .../src/ILLink/ILLink.Substitutions.xml | 5 - .../src/Resources/Strings.resx | 369 -- .../src/System.Private.Reflection.Core.csproj | 200 - .../Runtime/General/NonOverriddenApis.cs | 217 -- ...EnvironmentImplementation.MappingTables.cs | 30 +- ...PointerTypeFieldAccessorForStaticFields.cs | 4 +- ...ferenceTypeFieldAccessorForStaticFields.cs | 4 +- .../ValueTypeFieldAccessorForStaticFields.cs | 4 +- .../MissingMetadataExceptionCreator.cs | 23 +- ...System.Private.Reflection.Execution.csproj | 1 - .../Runtime/TypeLoader/EETypeCreator.cs | 2 +- .../Runtime/TypeLoader/GenericDictionary.cs | 2 +- .../TypeLoader/GenericDictionaryCell.cs | 18 +- .../Internal/Runtime/TypeLoader/ModuleList.cs | 10 +- .../TypeLoader/NativeLayoutFieldAlgorithm.cs | 4 +- .../TypeLoader/NativeLayoutFieldDesc.cs | 2 + .../NoMetadataFieldLayoutAlgorithm.cs | 4 +- .../Runtime/TypeLoader/TypeBuilder.cs | 22 +- .../Runtime/TypeLoader/TypeBuilderState.cs | 4 +- ...peLoaderEnvironment.LdTokenResultLookup.cs | 14 +- .../TypeLoaderEnvironment.Metadata.cs | 2 +- .../TypeLoaderEnvironment.NamedTypeLookup.cs | 8 +- .../TypeLoaderEnvironment.SignatureParsing.cs | 2 +- .../TypeLoader/TypeLoaderEnvironment.cs | 15 + .../Internal/TypeSystem/TypeDesc.Runtime.cs | 8 +- .../TypeSystem/TypeSystemContext.Runtime.cs | 4 +- .../src/System.Private.TypeLoader.csproj | 4 - .../src/System/Runtime/RuntimeImports.cs | 6 +- src/coreclr/nativeaot/docs/optimizing.md | 19 +- .../nativeaot/docs/reflection-free-mode.md | 2 +- src/coreclr/nativeaot/nativeaot.sln | 2 - src/coreclr/pal/inc/pal.h | 153 + src/coreclr/pal/inc/pal_endian.h | 2 +- src/coreclr/pal/inc/rt/intsafe.h | 1401 ------- src/coreclr/pal/inc/rt/palrt.h | 8 + src/coreclr/pal/inc/unixasmmacros.inc | 4 +- src/coreclr/pal/inc/unixasmmacrosppc64le.inc | 37 + src/coreclr/pal/src/CMakeLists.txt | 2 + .../pal/src/arch/ppc64le/asmconstants.h | 89 + .../arch/ppc64le/callsignalhandlerwrapper.S | 31 + src/coreclr/pal/src/arch/ppc64le/context2.S | 188 + src/coreclr/pal/src/arch/ppc64le/debugbreak.S | 10 + .../pal/src/arch/ppc64le/exceptionhelper.S | 63 + .../pal/src/arch/ppc64le/processor.cpp | 21 + .../src/arch/ppc64le/signalhandlerhelper.cpp | 68 + src/coreclr/pal/src/cruntime/file.cpp | 2 +- src/coreclr/pal/src/cruntime/printf.cpp | 22 +- src/coreclr/pal/src/cruntime/printfcpp.cpp | 18 +- .../pal/src/cruntime/silent_printf.cpp | 4 +- .../pal/src/exception/remote-unwind.cpp | 63 +- src/coreclr/pal/src/exception/seh-unwind.cpp | 60 + src/coreclr/pal/src/file/filetime.cpp | 12 +- src/coreclr/pal/src/include/pal/context.h | 89 + src/coreclr/pal/src/include/pal/virtual.h | 13 +- src/coreclr/pal/src/locale/utf8.cpp | 2 +- src/coreclr/pal/src/map/map.cpp | 8 +- src/coreclr/pal/src/map/virtual.cpp | 24 +- src/coreclr/pal/src/misc/cgroup.cpp | 99 +- src/coreclr/pal/src/misc/perfjitdump.cpp | 2 + src/coreclr/pal/src/misc/sysinfo.cpp | 91 +- src/coreclr/pal/src/misc/time.cpp | 16 +- src/coreclr/pal/src/safecrt/input.inl | 8 +- src/coreclr/pal/src/safecrt/wcslwr_s.cpp | 2 +- src/coreclr/pal/src/thread/context.cpp | 58 +- src/coreclr/scripts/superpmi.py | 14 + src/coreclr/scripts/superpmi_aspnet.py | 4 +- .../Common/Compiler/DisplayNameHelpers.cs | 2 +- .../Internal/Runtime/EETypeBuilderHelpers.cs | 2 +- .../Common/Internal/Runtime/ModuleHeaders.cs | 2 +- .../tools/Common/JitInterface/CorInfoBase.cs | 349 +- .../Common/JitInterface/CorInfoHelpFunc.cs | 7 +- .../tools/Common/JitInterface/CorInfoImpl.cs | 114 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 6 +- .../ThunkGenerator/ThunkInput.txt | 1 + src/coreclr/tools/Common/Pgo/PgoFormat.cs | 1 + .../Common/ExplicitLayoutValidator.cs | 2 +- .../Common/TypeSystem/Common/FieldDesc.cs | 3 + .../Common/FieldForInstantiatedType.cs | 5 + .../TypeSystem/Common/InstantiatedType.cs | 2 +- .../Common/TypeHashingAlgorithms.cs | 2 +- .../tools/Common/TypeSystem/Ecma/EcmaField.cs | 13 + .../TypeSystem/Ecma/EcmaSignatureParser.cs | 19 + .../tools/Common/TypeSystem/Ecma/EcmaType.cs | 7 +- .../IL/Stubs/PInvokeLazyFixupField.cs | 2 + .../TypeSystem/Interop/IL/InlineArrayType.cs | 1 + .../TypeSystem/Interop/IL/NativeStructType.cs | 2 + .../TypeSystemMetadataEmitter.cs | 228 +- src/coreclr/tools/aot/.editorconfig | 81 + .../Compiler/BodySubstitution.cs | 56 + .../Compiler/BodySubstitutionParser.cs | 172 + .../Compiler/Compilation.cs | 7 + .../Compiler/Dataflow/ReflectionMarker.cs | 4 +- .../Dataflow/ReflectionMethodBodyScanner.cs | 8 +- .../DependencyAnalysis/CanonicalEETypeNode.cs | 5 + .../ConstructedEETypeNode.cs | 5 + ...CustomAttributeBasedDependencyAlgorithm.cs | 26 +- .../Compiler/DependencyAnalysis/EETypeNode.cs | 19 +- .../DependencyAnalysis/FieldMetadataNode.cs | 2 +- .../DependencyAnalysis/GCStaticsNode.cs | 1 + .../GenericDictionaryNode.cs | 9 + .../DependencyAnalysis/MethodMetadataNode.cs | 2 +- .../DependencyAnalysis/NodeFactory.cs | 11 + .../DependencyAnalysis/NonGCStaticsNode.cs | 1 + .../ReadyToRunGenericHelperNode.cs | 2 + .../ReflectableFieldNode.cs | 105 + .../DependencyAnalysis/ThreadStaticsNode.cs | 3 +- .../DependencyAnalysis/TypeMetadataNode.cs | 19 +- .../Compiler/ExternSymbolMappedField.cs | 1 + .../Compiler/FeatureSwitchManager.cs | 165 +- .../Compiler/IRootingServiceProvider.cs | 1 + .../Compiler/LazyGenerics/GraphBuilder.cs | 7 +- .../Compiler/MetadataManager.cs | 44 +- .../Compiler/ProcessLinkerXmlBase.cs | 29 +- .../Compiler/RootingHelpers.cs | 95 +- .../Compiler/RootingServiceProvider.cs | 6 + .../Compiler/UsageBasedMetadataManager.cs | 289 +- .../IL/ILImporter.Scanner.cs | 5 +- .../ILCompiler.Compiler.csproj | 3 + .../aot/ILCompiler.Diagnostics/PdbWriter.cs | 7 +- .../SymNgenWriterWrapper.cs | 1 + .../ReadyToRunCodegenNodeFactory.cs | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 65 +- .../JitInterface/CorInfoImpl.RyuJit.cs | 19 +- .../ILTestAssembly/Signature.il | 2 + .../SignatureTests.cs | 29 + src/coreclr/tools/aot/ILCompiler/Program.cs | 19 +- .../AddedPseudoAttributeAttribute.cs | 15 + .../BaseExpectedLinkedBehaviorAttribute.cs | 16 + .../Assertions/BaseInAssemblyAttribute.cs | 9 + .../BaseMemberAssertionAttribute.cs | 15 + .../Assertions/CreatedMemberAttribute.cs | 18 + .../Assertions/DependencyRecordedAttribute.cs | 20 + .../Assertions/DisplayNameAttribute.cs | 12 + .../Assertions/EnableLoggerAttribute.cs | 9 + .../Assertions/ExpectBodyModifiedAttribute.cs | 12 + ...ResolvedDocumentationSignatureAttribute.cs | 14 + ...xpectExceptionHandlersModifiedAttribute.cs | 12 + ...eneratedDocumentationSignatureAttribute.cs | 14 + .../ExpectLocalsModifiedAttribute.cs | 12 + ...ResolvedDocumentationSignatureAttribute.cs | 14 + ...resolvedDocumentationSignatureAttribute.cs | 14 + .../ExpectedInstructionSequenceAttribute.cs | 17 + ...tionSequenceOnMemberInAssemblyAttribute.cs | 35 + .../ExpectedLocalsSequenceAttribute.cs | 23 + .../Assertions/ExpectedNoWarningsAttribute.cs | 17 + .../Assertions/ExpectedWarningAttribute.cs | 30 + .../Assertions/IgnoreTestCaseAttribute.cs | 18 + ...ptAllTypesAndMembersInAssemblyAttribute.cs | 17 + .../Assertions/KeptAssemblyAttribute.cs | 21 + .../Assertions/KeptAttribute.cs | 12 + .../Assertions/KeptAttributeAttribute.cs | 24 + .../KeptAttributeInAssemblyAttribute.cs | 71 + ...KeptAttributeOnFixedBufferTypeAttribute.cs | 23 + .../Assertions/KeptBackingFieldAttribute.cs | 12 + .../KeptBaseOnTypeInAssemblyAttribute.cs | 37 + .../Assertions/KeptBaseTypeAttribute.cs | 25 + .../KeptDelegateCacheFieldAttribute.cs | 17 + .../Assertions/KeptEventAddMethodAttribute.cs | 12 + .../KeptEventRemoveMethodAttribute.cs | 12 + .../Assertions/KeptExportedTypeAttribute.cs | 20 + .../Assertions/KeptFixedBufferAttribute.cs | 12 + .../Assertions/KeptInitializerData.cs | 22 + .../Assertions/KeptInterfaceAttribute.cs | 26 + .../KeptInterfaceOnTypeInAssemblyAttribute.cs | 37 + .../Assertions/KeptMemberAttribute.cs | 18 + .../KeptMemberInAssemblyAttribute.cs | 34 + .../KeptModuleReferenceAttribute.cs | 20 + .../Assertions/KeptReferenceAttribute.cs | 20 + .../KeptReferencesInAssemblyAttribute.cs | 20 + .../Assertions/KeptResourceAttribute.cs | 20 + .../KeptResourceInAssemblyAttribute.cs | 23 + .../Assertions/KeptSecurityAttribute.cs | 23 + .../Assertions/KeptSymbolsAttribute.cs | 17 + .../Assertions/KeptTypeInAssemblyAttribute.cs | 27 + .../Assertions/LogContainsAttribute.cs | 26 + .../Assertions/LogDoesNotContainAttribute.cs | 26 + .../Assertions/NoLinkedOutputAttribute.cs | 13 + .../Assertions/ProducedBy.cs | 21 + .../Assertions/RemovedAssemblyAttribute.cs | 21 + .../Assertions/RemovedAssemblyReference.cs | 18 + .../Assertions/RemovedAttributeInAssembly.cs | 71 + .../Assertions/RemovedForwarderAttribute.cs | 18 + ...movedInterfaceOnTypeInAssemblyAttribute.cs | 37 + .../RemovedMemberInAssemblyAttribute.cs | 32 + .../Assertions/RemovedNameValueAttribute.cs | 15 + .../RemovedPseudoAttributeAttribute.cs | 15 + .../RemovedResourceInAssemblyAttribute.cs | 23 + .../Assertions/RemovedSymbolsAttribute.cs | 17 + .../RemovedTypeInAssemblyAttribute.cs | 27 + .../SkipKeptItemsValidationAttribute.cs | 13 + .../Assertions/SkipPeVerifyAttribute.cs | 29 + .../SkipRemainingErrorsValidationAttribute.cs | 13 + .../TestCaseRequirementsAttribute.cs | 17 + .../Assertions/TestRunCharacteristics.cs | 17 + .../VerifyMetadataNamesAttribute.cs | 15 + .../Helpers/DataFlowStringExtensions.cs | 42 + .../Helpers/DataFlowTypeExtensions.cs | 43 + .../Helpers/PlatformAssemblies.cs | 14 + .../Metadata/BaseMetadataAttribute.cs | 13 + .../Metadata/DefineAttribute.cs | 17 + .../Metadata/IgnoreDescriptorsAttribute.cs | 15 + .../Metadata/IgnoreLinkAttributesAttribute.cs | 15 + .../Metadata/IgnoreSubstitutionsAttribute.cs | 15 + .../Metadata/Il8nAttribute.cs | 18 + ...eepTypeForwarderOnlyAssembliesAttribute.cs | 17 + .../Metadata/NotATestCaseAttribute.cs | 12 + .../Metadata/ReferenceAttribute.cs | 18 + .../Metadata/ReferenceDependencyAttribute.cs | 17 + .../Metadata/SandboxDependencyAttribute.cs | 24 + .../SetupCSharpCompilerToUseAttribute.cs | 17 + .../Metadata/SetupCompileAfterAttribute.cs | 36 + .../Metadata/SetupCompileArgumentAttribute.cs | 17 + .../SetupCompileAsLibraryAttribute.cs | 12 + .../SetupCompileAssemblyNameAttribute.cs | 17 + .../Metadata/SetupCompileBeforeAttribute.cs | 58 + .../Metadata/SetupCompileResourceAttribute.cs | 17 + .../Metadata/SetupLinkAttributesFile.cs | 15 + .../Metadata/SetupLinkerActionAttribute.cs | 17 + .../Metadata/SetupLinkerArgumentAttribute.cs | 24 + .../SetupLinkerDefaultActionAttribute.cs | 17 + .../Metadata/SetupLinkerDescriptorFile.cs | 15 + .../SetupLinkerKeepDebugMembersAttribute.cs | 17 + ...SetupLinkerLinkPublicAndFamilyAttribute.cs | 12 + .../SetupLinkerLinkSymbolsAttribute.cs | 17 + .../SetupLinkerResponseFileAttribute.cs | 17 + .../SetupLinkerSubstitutionFileAttribute.cs | 17 + .../Metadata/SetupLinkerTrimModeAttribute.cs | 17 + .../Metadata/SkipUnresolvedAttribute.cs | 15 + .../Metadata/StripDescriptorsAttribute.cs | 15 + .../Metadata/StripLinkAttributesAttribute.cs | 15 + .../Metadata/StripSubstitutionsAttribute.cs | 15 + ...ono.Linker.Tests.Cases.Expectations.csproj | 10 + .../Support/IntrinsicAttribute.cs | 12 + .../RemoveAttributeInstancesAttribute.cs | 17 + .../DataFlow/AssemblyQualifiedNameDataflow.cs | 163 + .../DataFlow/EmptyArrayIntrinsicsDataFlow.cs | 60 + .../DataFlow/GetInterfaceDataFlow.cs | 198 + .../GetNestedTypeOnAllAnnotatedType.cs | 141 + .../DataFlow/GetTypeDataFlow.cs | 220 ++ .../DataFlow/GetTypeInfoDataFlow.cs | 54 + .../DataFlow/MemberTypesRelationships.cs | 275 ++ .../DataFlow/TypeInfoAsTypeDataFlow.cs | 55 + .../DataFlow/UnsafeDataFlow.cs | 68 + .../Mono.Linker.Tests.Cases.csproj | 17 + .../Mono.Linker.Tests.Cases/Repro/Program.cs | 30 + .../RequiresCapability/BasicRequires.cs | 215 + .../Extensions/CecilExtensions.cs | 368 ++ .../Mono.Linker.Tests/Extensions/NiceIO.cs | 864 ++++ .../Mono.Linker.Tests.csproj | 51 + .../Mono.Linker.Tests/TestCases/TestCase.cs | 59 + .../TestCases/TestDatabase.cs | 76 + .../Mono.Linker.Tests/TestCases/TestSuites.cs | 45 + .../TestCasesRunner/AssemblyChecker.cs | 960 +++++ .../TestCasesRunner/BaseMetadataProvider.cs | 96 + .../TestCasesRunner/CompilerOptions.cs | 20 + .../TestCasesRunner/ExpectationsProvider.cs | 26 + .../TestCasesRunner/FormattingUtils.cs | 64 + .../TestCasesRunner/ILCompilerDriver.cs | 137 + .../TestCasesRunner/ILCompilerOptions.cs | 16 + .../ILCompilerOptionsBuilder.cs | 253 ++ .../ILCompilerTestCaseResult.cs | 31 + .../TestCasesRunner/ILInputCompiler.cs | 93 + .../TestCasesRunner/IgnoreTestException.cs | 12 + .../ManagedCompilationResult.cs | 20 + .../TestCasesRunner/ObjectFactory.cs | 41 + .../TestCasesRunner/PathUtilities.cs | 35 + .../TestCasesRunner/ResultChecker.cs | 405 ++ .../TestCasesRunner/SetupCompileInfo.cs | 23 + .../SourceAndDestinationPair.cs | 15 + .../TestCaseAssemblyResolver.cs | 43 + .../TestCasesRunner/TestCaseCollector.cs | 165 + .../TestCaseCompilationMetadataProvider.cs | 242 ++ .../TestCasesRunner/TestCaseCompiler.cs | 411 ++ .../TestCasesRunner/TestCaseLinkerOptions.cs | 36 + .../TestCaseMetadataProvider.cs | 141 + .../TestCasesRunner/TestCaseSandbox.cs | 195 + .../TestCasesRunner/TestLogWriter.cs | 57 + .../TestCasesRunner/TestRunner.cs | 165 + src/coreclr/tools/aot/ilc.sln | 68 +- .../tools/aot/jitinterface/jitinterface.h | 10 + src/coreclr/tools/dotnet-pgo/MibcEmitter.cs | 2 + .../TypeRefTypeSystemContext.cs | 4 +- .../TypeRefTypeSystemField.cs | 6 +- .../TypeRefTypeSystemType.cs | 4 +- .../tools/superpmi/mcs/verbdumpmap.cpp | 8 +- .../tools/superpmi/mcs/verbjitflags.cpp | 8 +- .../superpmi-shared/methodcontext.cpp | 11 +- .../superpmi/superpmi-shared/methodcontext.h | 5 +- .../superpmi-shared/spmidumphelper.cpp | 1 + .../superpmi-shim-collector/icorjitinfo.cpp | 7 + .../superpmi-shim-counter/icorjitinfo.cpp | 8 + .../superpmi-shim-simple/icorjitinfo.cpp | 7 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 5 + .../tools/superpmi/superpmi/superpmi.cpp | 15 +- .../unwinder/ppc64le/unwinder_ppc64le.cpp | 11 + src/coreclr/utilcode/CMakeLists.txt | 1 - src/coreclr/utilcode/clrconfig.cpp | 14 +- src/coreclr/utilcode/debug.cpp | 8 +- src/coreclr/utilcode/executableallocator.cpp | 3 +- src/coreclr/utilcode/iallocator.cpp | 9 - src/coreclr/utilcode/prettyprintsig.cpp | 8 +- src/coreclr/utilcode/sstring.cpp | 116 +- src/coreclr/utilcode/util.cpp | 162 +- src/coreclr/vm/CMakeLists.txt | 2 - src/coreclr/vm/ClrEtwAll.man | 35 +- src/coreclr/vm/amd64/Context.asm | 16 +- .../vm/amd64/JitHelpers_InlineGetThread.asm | 13 +- src/coreclr/vm/amd64/JitHelpers_Slow.asm | 12 +- .../vm/amd64/RedirectedHandledJITCase.asm | 22 - src/coreclr/vm/amd64/asmconstants.h | 12 - src/coreclr/vm/amd64/cgencpu.h | 41 + src/coreclr/vm/amd64/excepamd64.cpp | 9 +- src/coreclr/vm/amd64/excepcpu.h | 2 +- src/coreclr/vm/amd64/virtualcallstubcpu.hpp | 37 +- src/coreclr/vm/appdomain.cpp | 8 +- src/coreclr/vm/appdomain.hpp | 6 +- src/coreclr/vm/arm/asmconstants.h | 9 - src/coreclr/vm/arm/cgencpu.h | 2 +- src/coreclr/vm/arm/ehhelpers.asm | 23 - src/coreclr/vm/arm/exceparm.cpp | 4 +- src/coreclr/vm/arm/excepcpu.h | 2 +- src/coreclr/vm/arm64/asmhelpers.asm | 23 - src/coreclr/vm/arm64/excepcpu.h | 2 +- src/coreclr/vm/array.cpp | 11 +- src/coreclr/vm/assembly.cpp | 9 +- src/coreclr/vm/assemblybinder.h | 2 +- src/coreclr/vm/assemblynative.cpp | 25 +- src/coreclr/vm/assemblynative.hpp | 2 +- src/coreclr/vm/assemblyspec.cpp | 20 +- src/coreclr/vm/bundle.cpp | 5 +- src/coreclr/vm/ceeload.cpp | 28 +- src/coreclr/vm/ceeload.h | 4 +- src/coreclr/vm/ceemain.cpp | 29 +- src/coreclr/vm/class.cpp | 14 +- src/coreclr/vm/class.h | 10 +- src/coreclr/vm/classhash.cpp | 6 +- src/coreclr/vm/classlayoutinfo.cpp | 10 +- src/coreclr/vm/clsload.cpp | 8 +- src/coreclr/vm/codeman.cpp | 33 +- src/coreclr/vm/codepitchingmanager.cpp | 12 +- src/coreclr/vm/codeversion.cpp | 2 +- src/coreclr/vm/comcache.cpp | 10 +- src/coreclr/vm/comcache.h | 6 +- src/coreclr/vm/comcallablewrapper.cpp | 27 +- src/coreclr/vm/comcallablewrapper.h | 10 +- src/coreclr/vm/comconnectionpoints.cpp | 8 +- src/coreclr/vm/comdelegate.cpp | 12 +- src/coreclr/vm/common.h | 12 - src/coreclr/vm/comsynchronizable.cpp | 5 +- src/coreclr/vm/comsynchronizable.h | 2 - src/coreclr/vm/comtoclrcall.cpp | 14 +- src/coreclr/vm/comutilnative.cpp | 169 +- src/coreclr/vm/coreassemblyspec.cpp | 8 +- src/coreclr/vm/corelib.h | 7 +- src/coreclr/vm/corhost.cpp | 60 +- src/coreclr/vm/crst.cpp | 4 +- src/coreclr/vm/crst.h | 4 +- src/coreclr/vm/ctxtcall.h | 409 -- src/coreclr/vm/customattribute.cpp | 26 +- src/coreclr/vm/customattribute.h | 1 - src/coreclr/vm/dataimage.h | 19 - src/coreclr/vm/debugdebugger.cpp | 26 +- src/coreclr/vm/disassembler.cpp | 4 +- src/coreclr/vm/dllimport.cpp | 7 +- src/coreclr/vm/domainassembly.cpp | 4 +- src/coreclr/vm/dwbucketmanager.hpp | 12 +- src/coreclr/vm/dynamicmethod.cpp | 2 +- src/coreclr/vm/ecalllist.h | 3 - src/coreclr/vm/eeconfig.cpp | 65 +- src/coreclr/vm/eehash.inl | 4 +- src/coreclr/vm/eepolicy.cpp | 2 +- src/coreclr/vm/encee.cpp | 7 +- .../vm/eventing/eventpipe/ep-rt-coreclr.h | 3 +- src/coreclr/vm/eventreporter.cpp | 2 +- src/coreclr/vm/excep.cpp | 204 +- src/coreclr/vm/excep.h | 3 - src/coreclr/vm/exceptionhandling.cpp | 51 +- src/coreclr/vm/finalizerthread.cpp | 2 +- src/coreclr/vm/gccover.cpp | 38 +- src/coreclr/vm/gcenv.os.cpp | 47 +- src/coreclr/vm/gchelpers.cpp | 2 +- src/coreclr/vm/gdbjit.cpp | 15 +- src/coreclr/vm/genericdict.cpp | 4 +- src/coreclr/vm/generics.cpp | 8 +- src/coreclr/vm/genmeth.cpp | 3 +- src/coreclr/vm/hash.cpp | 6 +- src/coreclr/vm/hosting.cpp | 53 +- src/coreclr/vm/i386/excepx86.cpp | 6 +- src/coreclr/vm/i386/gmsx86.cpp | 1 + src/coreclr/vm/i386/jitinterfacex86.cpp | 24 +- src/coreclr/vm/i386/stublinkerx86.cpp | 2 +- src/coreclr/vm/ilmarshalers.cpp | 21 +- src/coreclr/vm/ilstubresolver.cpp | 6 +- src/coreclr/vm/instmethhash.h | 4 +- .../vm/interoplibinterface_comwrappers.cpp | 9 +- src/coreclr/vm/interoplibinterface_objc.cpp | 6 +- src/coreclr/vm/interoputil.cpp | 2 +- src/coreclr/vm/invokeutil.cpp | 20 +- src/coreclr/vm/jithelpers.cpp | 403 +- src/coreclr/vm/jitinterface.cpp | 39 +- src/coreclr/vm/jitinterface.h | 2 +- src/coreclr/vm/listlock.h | 4 +- src/coreclr/vm/loaderallocator.cpp | 19 +- src/coreclr/vm/loongarch64/excepcpu.h | 2 +- src/coreclr/vm/metasig.h | 5 +- src/coreclr/vm/method.cpp | 52 +- src/coreclr/vm/method.hpp | 2 +- src/coreclr/vm/methodtable.cpp | 44 +- src/coreclr/vm/methodtable.h | 19 +- src/coreclr/vm/methodtablebuilder.cpp | 9 +- src/coreclr/vm/mlinfo.cpp | 5 +- src/coreclr/vm/mngstdinterfaces.h | 2 +- src/coreclr/vm/multicorejit.cpp | 3 +- src/coreclr/vm/multicorejitplayer.cpp | 2 +- src/coreclr/vm/nativeeventsource.cpp | 10 + src/coreclr/vm/nativeeventsource.h | 1 + src/coreclr/vm/nativelibrary.cpp | 15 +- src/coreclr/vm/object.h | 30 +- src/coreclr/vm/olecontexthelpers.cpp | 8 +- src/coreclr/vm/olecontexthelpers.h | 4 +- src/coreclr/vm/olevariant.cpp | 166 +- src/coreclr/vm/peassembly.cpp | 6 +- src/coreclr/vm/peassembly.inl | 4 +- src/coreclr/vm/peimage.cpp | 8 +- src/coreclr/vm/peimage.inl | 2 +- src/coreclr/vm/peimagelayout.cpp | 10 +- src/coreclr/vm/peimagelayout.inl | 4 +- src/coreclr/vm/pgo.cpp | 21 +- src/coreclr/vm/ppc64le/unixstubs.cpp | 12 + src/coreclr/vm/profilinghelper.cpp | 6 +- src/coreclr/vm/proftoeeinterfaceimpl.cpp | 4 +- src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/sourceline.cpp | 328 -- src/coreclr/vm/sourceline.h | 43 - src/coreclr/vm/spinlock.cpp | 4 +- src/coreclr/vm/spinlock.h | 4 +- src/coreclr/vm/stackcontents.h | 124 - src/coreclr/vm/stackwalk.cpp | 7 + src/coreclr/vm/stdinterfaces.cpp | 2 +- src/coreclr/vm/stdinterfaces_wrapper.cpp | 2 +- src/coreclr/vm/stubgen.cpp | 13 +- src/coreclr/vm/stubhelpers.cpp | 37 - src/coreclr/vm/stublink.cpp | 4 +- src/coreclr/vm/syncblk.cpp | 14 +- src/coreclr/vm/syncblk.h | 30 +- src/coreclr/vm/syncblk.inl | 17 + src/coreclr/vm/syncclean.cpp | 8 +- src/coreclr/vm/synch.cpp | 10 +- src/coreclr/vm/threadpoolrequest.cpp | 10 +- src/coreclr/vm/threadpoolrequest.h | 4 +- src/coreclr/vm/threads.cpp | 139 +- src/coreclr/vm/threads.h | 87 +- src/coreclr/vm/threadsuspend.cpp | 672 ++-- src/coreclr/vm/typedesc.cpp | 6 +- src/coreclr/vm/typedesc.h | 2 +- src/coreclr/vm/typehash.h | 4 +- src/coreclr/vm/typeparse.cpp | 5 +- src/coreclr/vm/util.cpp | 17 - src/coreclr/vm/util.hpp | 162 +- src/coreclr/vm/vars.hpp | 11 + src/coreclr/vm/virtualcallstub.cpp | 14 +- src/coreclr/vm/win32threadpool.cpp | 33 +- src/coreclr/vm/win32threadpool.h | 6 +- .../Bundle/Manifest.cs | 2 +- .../ComHost/ClsidMap.cs | 4 +- .../pkg/projects/netcoreappRIDs.props | 6 + .../MultiArchInstallLocation.cs | 82 + .../tests/HostActivation.Tests/SDKLookup.cs | 2 +- src/installer/tests/TestUtils/DotNetCli.cs | 30 +- .../tests/TestUtils/TestUtils.csproj | 2 +- .../Interop.X509Chain.cs | 4 - .../Interop.Sign.cs | 22 + .../Interop.SimpleDigestHash.cs | 4 +- .../Interop.Symmetric.cs | 8 - ...rop.ProcFsStat.TryReadProcessStatusInfo.cs | 1 + .../Unix/System.Native/Interop.Permissions.cs | 33 - .../Interop.NetSecurityNative.cs | 88 +- .../Interop.OpenSsl.cs | 2 +- .../Windows/Advapi32/Interop.LsaLookupSids.cs | 2 +- .../Windows/Crypt32/Interop.FindOidInfo.cs | 22 +- .../Windows/Crypt32/Interop.HashIdAlg.cs | 21 +- .../src/Interop/Windows/Interop.Errors.cs | 10 + .../Windows/IpHlpApi/Interop.FIXED_INFO.cs | 35 +- .../Interop/Windows/IpHlpApi/Interop.ICMP.cs | 31 +- .../IpHlpApi/Interop.IP_ADDR_STRING.cs | 12 +- .../IpHlpApi/Interop.NetworkInformation.cs | 89 +- ...itionMask.cs => Interop.GetCommandLine.cs} | 6 +- .../Kernel32/Interop.VerifyVersionExW.cs | 20 - .../Shell32/Interop.CommandLineToArgv.cs | 13 + .../GssSafeHandles.PlatformNotSupported.cs | 59 - .../Common/src/System/Console/ConsoleUtils.cs | 53 + .../Data/ProviderBase/DbMetaDataFactory.cs | 12 +- .../src/System/HashCodeRandomization.cs | 58 + .../src/System/IO/Archiving.Utils.Windows.cs | 35 +- .../Common/src/System/IO/Archiving.Utils.cs | 2 +- .../Common/src/System/IO/DelegatingStream.cs | 15 +- .../src/System/IO/ReadOnlyMemoryStream.cs | 14 +- .../Common/src/System/IO/RowConfigReader.cs | 2 +- ...extFlagsAdapterPal.PlatformNotSupported.cs | 22 - .../src/System/Net/Http/X509ResourceClient.cs | 9 +- .../aspnetcore/Http2/Hpack/IntegerDecoder.cs | 4 +- .../aspnetcore/Http2/Hpack/IntegerEncoder.cs | 4 +- .../Helpers/VariableLengthIntegerHelper.cs | 4 +- .../aspnetcore/Http3/QPack/QPackEncoder.cs | 10 +- .../src/System/Net/NTAuthentication.Common.cs | 57 +- .../System/Net/NTAuthentication.Managed.cs | 205 +- .../HostInformationPal.Windows.cs | 120 +- ...NegotiateStreamPal.PlatformNotSupported.cs | 124 - .../Net/Security/NegotiateStreamPal.Unix.cs | 29 +- .../Security/NegotiateStreamPal.Windows.cs | 211 +- .../System/Net/Security/SSPIHandleCache.cs | 11 +- .../Common/src/System/Net/SocketAddress.cs | 19 +- .../Common/src/System/Obsoletions.cs | 3 + .../Cryptography/Asn1Reader/AsnValueReader.cs | 7 + .../Security/Cryptography/Oids.Shared.cs | 2 + .../Common/src/System/Text/DBCSDecoder.cs | 6 +- .../Common/src/System/Text/OSEncoder.cs | 4 +- .../SingleFileTestRunner.cs | 15 +- .../System/IO/StreamConformanceTests.cs | 18 +- .../Common/tests/System/GenericMathHelpers.cs | 12 +- .../Net/Http/Http2LoopbackConnection.cs | 2 +- .../System/Net/Http/Http3LoopbackServer.cs | 18 +- .../HttpClientHandlerTest.Authentication.cs | 60 + ...ttpClientHandlerTest.ServerCertificates.cs | 10 +- .../Net/Security/FakeNegotiateServer.cs | 278 ++ .../System/Net/Security}/FakeNtlmServer.cs | 22 +- .../System/Reflection/InvokeEmitTests.cs | 56 + .../Reflection/InvokeInterpretedTests.cs | 53 + .../TestUtilities/System/PlatformDetection.cs | 1 + .../ComInterop/IDispatchComObject.cs | 2 +- .../RuntimeBinder/Semantics/Binding/Better.cs | 2 +- .../Semantics/GroupToArgsBinder.cs | 5 +- .../RuntimeBinder/Semantics/Operators.cs | 28 +- .../Semantics/Symbols/AggregateSymbol.cs | 6 +- .../CSharp/RuntimeBinder/SymbolTable.cs | 2 +- .../Diagnostics/Tracing/StubEnvironment.cs | 2 +- .../src/ConfigurationBinder.cs | 146 +- ...oft.Extensions.Configuration.Binder.csproj | 9 +- .../src/Resources/Strings.resx | 19 +- .../tests/ConfigurationBinderTests.cs | 664 +++- ...tensions.Configuration.Binder.Tests.csproj | 1 + .../src/ServiceProvider.cs | 2 +- .../PatternContexts/PatternContextLinear.cs | 2 +- .../Microsoft.Extensions.Hosting.Systemd.cs | 13 +- .../src/SystemdHostBuilderExtensions.cs | 67 +- .../tests/UseSystemdTests.cs | 26 +- ...soft.Extensions.Hosting.WindowsServices.cs | 6 +- ...owsServiceLifetimeHostBuilderExtensions.cs | 123 +- ...sions.Hosting.WindowsServices.Tests.csproj | 9 +- .../tests/UseWindowsServiceTests.cs | 93 +- .../src/HostingHostBuilderExtensions.cs | 18 +- .../tests/UnitTests/HostTests.cs | 32 + ...osoft.Extensions.Hosting.Unit.Tests.csproj | 2 +- .../Microsoft.Extensions.Logging.Console.cs | 7 + .../src/ConsoleLoggerOptions.cs | 37 + .../src/ConsoleLoggerProcessor.cs | 166 +- .../src/ConsoleLoggerProvider.cs | 18 +- .../src/ConsoleLoggerQueueFullMode.cs | 20 + ...icrosoft.Extensions.Logging.Console.csproj | 2 + .../src/Resources/Strings.resx | 9 + .../src/SimpleConsoleFormatter.cs | 2 +- .../ConsoleFormatterTests.cs | 4 +- .../ConsoleLoggerExtensionsTests.cs | 45 +- .../ConsoleLoggerProcessorTests.cs | 175 + .../ConsoleLoggerTest.cs | 93 +- ...ft.Extensions.Logging.Console.Tests.csproj | 1 + .../src/TraceSourceLoggerProvider.cs | 7 +- .../src/OptionsManager.cs | 2 +- .../src/OptionsMonitor.cs | 2 +- .../src/runtime.compatibility.json | 26 +- .../src/runtime.json | 19 +- .../src/runtimeGroups.props | 6 +- .../src/Microsoft/Win32/SystemEvents.cs | 8 +- .../src/Sgen.cs | 6 +- .../Collections/Concurrent/ConcurrentBag.cs | 4 +- .../src/System.Collections.Immutable.csproj | 3 +- .../Immutable/ImmutableArray_1.Builder.cs | 10 +- .../Collections/Immutable/ImmutableArray_1.cs | 4 +- .../Immutable/ImmutableList_1.Node.cs | 6 +- .../Specialized/NameObjectCollectionBase.cs | 4 +- .../Specialized/NameValueCollection.cs | 2 +- .../System/Collections/Generic/LinkedList.cs | 2 +- .../System.Collections/tests/default.rd.xml | 6 + .../AttributedExportDefinition.cs | 4 +- .../Composition/ContractNameServices.cs | 2 +- .../Hosting/AggregateExportProvider.cs | 2 +- .../Composition/Hosting/AssemblyCatalog.cs | 2 + .../Composition/Hosting/AtomicComposition.cs | 2 +- .../ComposablePartCatalogCollection.cs | 14 +- .../Hosting/CompositionContainer.cs | 2 +- .../Composition/Hosting/DirectoryCatalog.cs | 12 +- .../Composition/ImportAttribute.cs | 2 +- .../Composition/ReflectionModel/ImportType.cs | 2 +- .../ReflectionModelServices.cs | 2 +- .../Linq/ComponentModel/XComponentModel.cs | 6 +- .../DesigntimeLicenseContextSerializer.cs | 2 +- .../DesignTimeVisibleAttribute.cs | 6 +- .../System/ComponentModel/TypeDescriptor.cs | 2 - .../Hosting/Core/CompositionContract.cs | 4 +- .../Composition/TypedParts/ContractHelpers.cs | 6 +- .../TypedParts/Discovery/DiscoveredPart.cs | 3 +- .../TypedParts/Discovery/TypeInspector.cs | 2 +- .../Configuration/ApplicationSettingsBase.cs | 2 +- .../System/Configuration/ClientConfigPaths.cs | 3 +- .../Configuration/ConfigDefinitionUpdates.cs | 4 +- .../Configuration/ConfigurationElement.cs | 4 +- .../ConfigurationElementCollection.cs | 2 +- .../StringAttributeCollection.cs | 2 +- .../System.Console/src/System.Console.csproj | 2 + .../src/System/ConsolePal.Unix.cs | 47 +- .../System.Console/src/System/TermInfo.cs | 5 +- .../src/System/Data/Common/ByteStorage.cs | 2 +- .../System/Data/Common/DBCommandBuilder.cs | 5 +- .../System/Data/Common/DataRecordInternal.cs | 4 +- .../System/Data/Common/DbConnectionOptions.cs | 2 +- .../src/System/Data/Common/DecimalStorage.cs | 2 +- .../src/System/Data/Common/DoubleStorage.cs | 2 +- .../src/System/Data/Common/Int16Storage.cs | 2 +- .../src/System/Data/Common/Int32Storage.cs | 2 +- .../src/System/Data/Common/Int64Storage.cs | 2 +- .../src/System/Data/Common/SByteStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLByteStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLDecimalStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLDoubleStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLInt16Storage.cs | 2 +- .../Data/Common/SQLTypes/SQLInt32Storage.cs | 2 +- .../Data/Common/SQLTypes/SQLInt64Storage.cs | 2 +- .../Data/Common/SQLTypes/SQLMoneyStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLSingleStorage.cs | 2 +- .../Data/Common/SQLTypes/SQLStringStorage.cs | 4 +- .../src/System/Data/Common/SingleStorage.cs | 2 +- .../src/System/Data/Common/StringStorage.cs | 4 +- .../src/System/Data/Common/UInt16Storage.cs | 2 +- .../src/System/Data/Common/UInt32Storage.cs | 2 +- .../src/System/Data/Common/UInt64Storage.cs | 2 +- .../src/System/Data/ConstraintCollection.cs | 3 +- .../src/System/Data/ConstraintEnumerator.cs | 2 +- .../src/System/Data/DataColumn.cs | 4 +- .../Data/DataColumnPropertyDescriptor.cs | 13 +- .../src/System/Data/DataRelation.cs | 5 +- .../Data/DataRelationPropertyDescriptor.cs | 12 +- .../src/System/Data/DataTable.cs | 6 +- .../Data/DataTablePropertyDescriptor.cs | 12 +- .../src/System/Data/DataView.cs | 6 +- .../src/System/Data/Filter/BinaryNode.cs | 5 +- .../src/System/Data/Filter/DataExpression.cs | 2 +- .../src/System/Data/Filter/FunctionNode.cs | 2 +- .../src/System/Data/Filter/UnaryNode.cs | 2 +- .../src/System/Data/LinqDataView.cs | 2 +- .../Data/ProviderBase/DataReaderContainer.cs | 2 +- .../src/System/Data/SQLTypes/SQLBinary.cs | 4 +- .../src/System/Data/SQLTypes/SQLBoolean.cs | 4 +- .../src/System/Data/SQLTypes/SQLByte.cs | 4 +- .../src/System/Data/SQLTypes/SQLDateTime.cs | 4 +- .../src/System/Data/SQLTypes/SQLDecimal.cs | 13 +- .../src/System/Data/SQLTypes/SQLDouble.cs | 4 +- .../src/System/Data/SQLTypes/SQLGuid.cs | 24 +- .../src/System/Data/SQLTypes/SQLInt16.cs | 4 +- .../src/System/Data/SQLTypes/SQLInt32.cs | 4 +- .../src/System/Data/SQLTypes/SQLInt64.cs | 4 +- .../src/System/Data/SQLTypes/SQLMoney.cs | 6 +- .../src/System/Data/SQLTypes/SQLSingle.cs | 4 +- .../src/System/Data/SQLTypes/SQLString.cs | 6 +- .../src/System/Data/Selection.cs | 2 +- .../src/System/Data/SimpleType.cs | 4 +- .../src/System/Data/XMLSchema.cs | 46 +- .../src/System/Data/XmlDataLoader.cs | 5 +- .../src/System/Data/xmlsaver.cs | 16 +- .../src/System/Xml/DataPointer.cs | 2 +- .../src/System/Xml/XPathNodePointer.cs | 2 +- .../src/System/Xml/XmlDataDocument.cs | 24 +- .../System/Data/Common/DBConnectionString.cs | 2 +- .../System/Data/Common/DbConnectionOptions.cs | 14 +- .../Data/ProviderBase/DbConnectionPool.cs | 12 +- .../src/System/Data/Odbc/Odbc32.cs | 2 +- .../src/System/Data/Odbc/OdbcCommand.cs | 3 +- .../src/System/Data/Odbc/OdbcConnection.cs | 2 +- .../System/Data/Odbc/OdbcConnectionHelper.cs | 4 +- .../src/System/Data/Odbc/OdbcDataReader.cs | 12 +- .../src/System/Data/Odbc/OdbcError.cs | 4 +- .../System/Data/Odbc/OdbcMetaDataFactory.cs | 18 +- .../src/System/Data/Odbc/OdbcParameter.cs | 3 +- .../System/Data/Odbc/OdbcParameterHelper.cs | 7 +- .../System.Data.OleDb/src/ColumnBinding.cs | 2 +- .../src/DbConnectionOptions.cs | 7 +- .../src/DbParameterHelper.cs | 3 +- .../System.Data.OleDb/src/OleDbCommand.cs | 3 +- .../src/OleDbCommandBuilder.cs | 4 +- .../System.Data.OleDb/src/OleDbConnection.cs | 11 +- .../src/OleDbConnectionInternal.cs | 3 +- .../System.Data.OleDb/src/OleDbDataReader.cs | 4 +- .../System.Data.OleDb/src/OleDbError.cs | 9 +- .../System.Data.OleDb/src/OleDbException.cs | 3 +- .../System.Data.OleDb/src/OleDbParameter.cs | 3 +- .../System.Data.OleDb/src/OleDbStruct.cs | 9 +- .../System.Data.OleDb/src/RowBinding.cs | 4 +- .../src/System/Data/Common/AdapterUtil.cs | 4 +- .../Data/ProviderBase/DbConnectionHelper.cs | 7 +- .../Data/ProviderBase/DbConnectionPool.cs | 5 +- .../Data/ProviderBase/DbMetaDataFactory.cs | 12 +- .../Diagnostics/Activity.DateTime.corefx.cs | 2 - .../DiagnosticSourceEventSource.cs | 3 + .../Diagnostics/Metrics/MetricsEventSource.cs | 2 +- .../src/System.Diagnostics.EventLog.csproj | 4 +- .../System/Diagnostics/Reader/EventKeyword.cs | 4 +- .../System/Diagnostics/Reader/EventLevel.cs | 4 +- .../Diagnostics/Reader/EventLogException.cs | 35 +- .../System/Diagnostics/Reader/EventLogLink.cs | 4 +- .../Diagnostics/Reader/EventLogReader.cs | 2 +- .../Diagnostics/Reader/EventLogRecord.cs | 4 +- .../Diagnostics/Reader/EventLogWatcher.cs | 5 +- .../Diagnostics/Reader/EventMetadata.cs | 2 +- .../System/Diagnostics/Reader/EventOpcode.cs | 2 +- .../System/Diagnostics/Reader/EventTask.cs | 2 +- .../Diagnostics/Reader/NativeWrapper.cs | 15 +- .../Reader/EventLogSessionTests.cs | 12 + .../Diagnostics/FileVersionInfo.Unix.cs | 13 +- .../Diagnostics/FileVersionInfo.Windows.cs | 4 +- .../Diagnostics/SharedPerformanceCounter.cs | 4 +- .../src/System.Diagnostics.Process.csproj | 2 - .../src/System/Diagnostics/Process.NonUap.cs | 2 +- .../src/System/Diagnostics/Process.Unix.cs | 12 +- .../Diagnostics/ProcessManager.Win32.cs | 57 +- .../tests/ProcessTests.Unix.cs | 18 +- .../tests/ProcessTests.Windows.cs | 3 - .../tests/ProcessTests.cs | 6 +- .../src/System/Diagnostics/Switch.cs | 6 +- .../src/System/Diagnostics/TraceListener.cs | 4 +- .../TrimmingTests/EventSourceManifestTest.cs | 3 + .../AccountManagement/AD/ADAMStoreCtx.cs | 4 +- .../AccountManagement/AD/ADDNLinkedAttrSet.cs | 8 +- .../AccountManagement/AD/ADStoreCtx.cs | 18 +- .../AD/ADStoreCtx_LoadStore.cs | 4 +- .../AccountManagement/AD/ADStoreCtx_Query.cs | 9 +- .../AccountManagement/AD/RangeRetriever.cs | 2 +- .../AccountManagement/AD/SDSCache.cs | 6 +- .../AccountManagement/AD/SDSUtils.cs | 12 +- .../AccountManagement/AD/SidList.cs | 2 +- .../AuthenticablePrincipal.cs | 2 +- .../AccountManagement/ExtensionCache.cs | 10 +- .../AccountManagement/FindResultEnumerator.cs | 4 +- .../AccountManagement/PasswordInfo.cs | 2 +- .../AccountManagement/Principal.cs | 12 +- .../AccountManagement/PrincipalCollection.cs | 4 +- .../PrincipalCollectionEnumerator.cs | 2 +- .../AccountManagement/PrincipalSearcher.cs | 4 +- .../AccountManagement/SAM/SAMMembersSet.cs | 4 +- .../AccountManagement/SAM/SAMStoreCtx.cs | 8 +- .../AccountManagement/StoreCtx.cs | 6 +- .../TrackedCollectionEnumerator.cs | 2 +- .../AccountManagement/Utils.cs | 6 +- .../AccountManagement/interopt.cs | 10 +- .../Protocols/ldap/LdapConnection.cs | 2 +- .../ActiveDirectorySchemaClass.cs | 4 +- .../ActiveDirectorySchemaProperty.cs | 10 +- .../ActiveDirectory/ActiveDirectorySite.cs | 2 +- .../ActiveDirectorySiteLink.cs | 2 +- .../ActiveDirectorySiteLinkCollection.cs | 2 +- .../ActiveDirectory/ActiveDirectorySubnet.cs | 2 +- .../ActiveDirectory/ConfigSet.cs | 4 +- .../ActiveDirectory/DomainController.cs | 2 +- .../ForestTrustRelationshipInformation.cs | 2 +- .../ActiveDirectory/Locator.cs | 2 +- .../ActiveDirectory/ReplicationConnection.cs | 4 +- .../TrustRelationshipInformation.cs | 2 +- .../ActiveDirectory/Utils.cs | 6 +- .../DirectoryServices/DirectoryEntry.cs | 24 +- .../DirectoryServices/DirectorySearcher.cs | 14 +- .../src/System/Drawing/ClientUtils.cs | 4 +- .../src/System/Drawing/FontConverter.cs | 8 +- .../src/System/Drawing/Image.cs | 2 - .../src/System/Drawing/ImageAnimator.cs | 9 +- .../src/System/Drawing/ImageInfo.cs | 5 +- .../Drawing/Imaging/EncoderParameter.cs | 10 +- .../Drawing/Imaging/ImageCodecInfoPrivate.cs | 4 +- .../Drawing/Imaging/MetafileHeaderEmf.cs | 10 +- .../Drawing/Imaging/MetafileHeaderWmf.cs | 10 +- .../src/System/Drawing/Printing/PaperSize.cs | 2 +- .../src/System/Drawing/StringFormat.cs | 2 +- .../ref/System.Formats.Tar.cs | 17 +- .../src/Resources/Strings.resx | 9 +- .../src/System.Formats.Tar.csproj | 2 +- .../src/System/Formats/Tar/GnuTarEntry.cs | 57 +- .../PaxGlobalExtendedAttributesTarEntry.cs | 50 + .../src/System/Formats/Tar/PaxTarEntry.cs | 78 +- .../src/System/Formats/Tar/PosixTarEntry.cs | 35 +- .../src/System/Formats/Tar/TarEntry.Unix.cs | 3 +- .../src/System/Formats/Tar/TarEntry.cs | 124 +- .../src/System/Formats/Tar/TarFile.cs | 5 +- .../src/System/Formats/Tar/TarHeader.Read.cs | 167 +- .../src/System/Formats/Tar/TarHeader.Write.cs | 74 +- .../src/System/Formats/Tar/TarHeader.cs | 11 +- .../src/System/Formats/Tar/TarHelpers.cs | 107 +- .../src/System/Formats/Tar/TarReader.cs | 102 +- .../src/System/Formats/Tar/TarWriter.Unix.cs | 7 +- .../System/Formats/Tar/TarWriter.Windows.cs | 6 +- .../src/System/Formats/Tar/TarWriter.cs | 100 +- .../src/System/Formats/Tar/UstarTarEntry.cs | 23 +- .../src/System/Formats/Tar/V7TarEntry.cs | 14 +- .../tests/CompressedTar.Tests.cs | 2 +- .../tests/System.Formats.Tar.Tests.csproj | 9 + .../TarEntry/GnuTarEntry.Conversion.Tests.cs | 262 ++ .../TarEntry/PaxTarEntry.Conversion.Tests.cs | 345 ++ .../TarEntry.Conversion.Tests.Base.cs | 223 ++ .../tests/TarEntry/TarEntryV7.Tests.cs | 1 + .../UstarTarEntry.Conversion.Tests.cs | 262 ++ .../TarEntry/V7TarEntry.Conversion.Tests.cs | 236 ++ .../TarFile.ExtractToDirectory.File.Tests.cs | 23 + ...TarFile.ExtractToDirectory.Stream.Tests.cs | 46 +- .../TarReader.ExtractToFile.Tests.Unix.cs | 45 + .../TarReader.ExtractToFile.Tests.cs | 50 +- ...der.File.GlobalExtendedAttributes.Tests.cs | 86 + .../TarReader/TarReader.File.Tests.Base.cs | 620 +++ .../tests/TarReader/TarReader.File.Tests.cs | 730 +--- .../tests/TarTestsBase.Gnu.cs | 2 +- .../tests/TarTestsBase.Pax.cs | 42 +- .../System.Formats.Tar/tests/TarTestsBase.cs | 62 +- .../tests/TarWriter/TarWriter.Tests.cs | 19 +- .../TarWriter.WriteEntry.Entry.Gnu.Tests.cs | 9 +- .../TarWriter.WriteEntry.Entry.Pax.Tests.cs | 281 +- .../TarWriter.WriteEntry.Entry.Ustar.Tests.cs | 9 +- .../TarWriter.WriteEntry.Entry.V7.Tests.cs | 49 +- .../TarWriter.WriteEntry.File.Tests.Unix.cs | 29 +- ...TarWriter.WriteEntry.File.Tests.Windows.cs | 43 +- .../TarWriter.WriteEntry.File.Tests.cs | 62 +- .../TarWriter/TarWriter.WriteEntry.Tests.cs | 203 + .../IdnMappingIdnaConformanceTests.cs | 4 - .../NumberFormatInfo/NumberFormatInfoTests.cs | 16 + ...Extensions.ZipArchiveEntry.Extract.Unix.cs | 4 +- .../ref/System.IO.Compression.cs | 11 +- .../Compression/DeflateManaged/InputBuffer.cs | 2 +- .../System/IO/Compression/ZipArchiveEntry.cs | 32 +- .../tests/ZipArchive/zip_ReadTests.cs | 42 + .../AccessControl/DirectoryObjectSecurity.cs | 4 +- .../src/System/IO/FileSystemWatcher.Linux.cs | 39 +- .../src/System/IO/FileSystemWatcher.cs | 2 +- .../tests/Base/AllGetSetAttributes.cs | 10 +- .../tests/Base/BaseGetSetUnixFileMode.cs | 217 ++ .../tests/Base/FileGetSetAttributes.cs | 4 +- .../CreateDirectory_UnixFileMode.Unix.cs | 57 + .../CreateDirectory_UnixFileMode.Windows.cs | 17 + .../tests/Directory/Delete.cs | 1 - .../tests/Directory/Move.cs | 1 - .../tests/DirectoryInfo/GetSetUnixFileMode.cs | 20 + .../tests/DirectoryInfo/MoveTo.cs | 1 - .../tests/File/GetSetUnixFileMode.cs | 16 + .../File/GetSetUnixFileMode_SafeFileHandle.cs | 25 + .../System.IO.FileSystem/tests/File/Open.cs | 12 + .../tests/File/ReadWriteAllBytes.cs | 1 - .../tests/File/ReadWriteAllBytesAsync.cs | 1 - .../tests/File/ReadWriteAllLines.cs | 2 - .../tests/File/ReadWriteAllLinesAsync.cs | 1 - .../tests/File/ReadWriteAllText.cs | 1 - .../tests/File/ReadWriteAllTextAsync.cs | 1 - .../tests/FileInfo/GetSetUnixFileMode.cs | 16 + .../tests/FileInfo/Open.cs | 12 + .../tests/FileStream/FileStreamOptions.cs | 26 + .../tests/FileStream/ctor_options.Unix.cs | 59 + .../tests/FileStream/ctor_options.cs | 13 + .../tests/FileSystemTest.cs | 48 + .../tests/System.IO.FileSystem.Tests.csproj | 7 + .../src/System.IO.MemoryMappedFiles.csproj | 2 - .../MemoryMappedFile.Unix.cs | 8 +- .../MemoryMappedFile.CreateFromFile.Tests.cs | 2 - .../src/System/IO/Packaging/PackUriHelper.cs | 2 +- .../src/System/IO/Packaging/Package.cs | 10 +- .../src/System/IO/Packaging/PackagePart.cs | 2 +- .../src/System/IO/Packaging/ZipPackage.cs | 32 +- .../System/IO/Packaging/ZipStreamManager.cs | 25 +- .../src/System.IO.Pipes.csproj | 2 - .../src/System/IO/Pipes/PipeStream.Windows.cs | 6 +- .../src/System/IO/Ports/SerialPort.cs | 2 - .../src/System/IO/Ports/SerialStream.Unix.cs | 22 +- .../System/IO/Ports/SerialStream.Windows.cs | 16 +- .../System/Dynamic/BinaryOperationBinder.cs | 4 +- .../src/System/Dynamic/ConvertBinder.cs | 4 +- .../System/Dynamic/CreateInstanceBinder.cs | 4 +- .../src/System/Dynamic/DeleteIndexBinder.cs | 4 +- .../src/System/Dynamic/DeleteMemberBinder.cs | 4 +- .../src/System/Dynamic/GetIndexBinder.cs | 4 +- .../src/System/Dynamic/GetMemberBinder.cs | 4 +- .../src/System/Dynamic/InvokeBinder.cs | 4 +- .../src/System/Dynamic/InvokeMemberBinder.cs | 4 +- .../src/System/Dynamic/SetIndexBinder.cs | 4 +- .../src/System/Dynamic/SetMemberBinder.cs | 4 +- .../System/Dynamic/UnaryOperationBinder.cs | 4 +- .../Compiler/LambdaCompiler.Statements.cs | 2 +- .../Linq/Expressions/DebugViewWriter.cs | 15 +- .../Interpreter/InstructionList.cs | 3 +- .../Expressions/Interpreter/LightCompiler.cs | 2 +- .../Coalesce/BinaryCoalesceTests.cs | 2 +- .../tests/CompilerTests.cs | 2 +- .../tests/StackSpillerTests.cs | 42 +- ...aryArithmeticNegateCheckedNullableTests.cs | 2 +- .../tests/default.rd.xml | 18 + .../Partitioning/PartitionedDataSource.cs | 2 +- .../QueryOperators/BinaryQueryOperator.cs | 2 +- .../Parallel/QueryOperators/QuerySettings.cs | 2 +- .../QueryOperators/Unary/SortQueryOperator.cs | 2 +- .../QueryOperators/UnaryQueryOperator.cs | 2 +- .../src/System/Linq/ParallelEnumerable.cs | 4 +- .../src/System/Management/ManagementClass.cs | 2 +- .../System/Management/ManagementDateTime.cs | 30 +- .../System/Management/ManagementEventArgs.cs | 2 +- .../ManagementNamedValueCollection.cs | 3 +- .../src/System/Management/ManagementObject.cs | 27 +- .../Management/ManagementObjectCollection.cs | 4 +- .../Management/ManagementObjectSearcher.cs | 6 +- .../System/Management/ManagementOptions.cs | 35 +- .../src/System/Management/ManagementPath.cs | 5 +- .../src/System/Management/ManagementQuery.cs | 43 +- .../src/System/Management/ManagementScope.cs | 7 +- .../src/System/Management/Method.cs | 2 +- .../src/System/Management/Property.cs | 2 +- .../src/System/Management/PropertySet.cs | 4 +- .../src/System/Management/Qualifier.cs | 2 +- .../src/System/Management/QualifierSet.cs | 8 +- .../src/System/Management/WMIGenerator.cs | 94 +- .../src/System/Buffers/Text/Base64Decoder.cs | 109 +- .../src/System/Buffers/Text/Base64Encoder.cs | 88 +- .../tests/Base64/Base64TestHelper.cs | 2 +- .../ref/System.Net.Http.Json.cs | 20 + .../src/System.Net.Http.Json.csproj | 1 + .../Json/HttpClientJsonExtensions.Delete.cs | 179 + .../HttpClientJsonExtensionsTests.cs | 46 + ...ttpClientHandlerTestBase.WinHttpHandler.cs | 4 +- .../FunctionalTests/PlatformHandlerTest.cs | 5 +- .../src/Resources/Strings.resx | 40 +- .../src/System.Net.Http.csproj | 97 - .../Http/Headers/AuthenticationHeaderValue.cs | 18 +- .../Net/Http/Headers/BaseHeaderParser.cs | 2 +- .../Http/Headers/CacheControlHeaderValue.cs | 8 +- .../Headers/ContentDispositionHeaderValue.cs | 2 +- .../Http/Headers/ContentRangeHeaderValue.cs | 20 +- .../Net/Http/Headers/EntityTagHeaderValue.cs | 6 +- .../Net/Http/Headers/HeaderUtilities.cs | 4 +- .../Net/Http/Headers/MediaTypeHeaderValue.cs | 6 +- .../Net/Http/Headers/NameValueHeaderValue.cs | 18 +- .../NameValueWithParametersHeaderValue.cs | 2 +- .../Net/Http/Headers/ProductHeaderValue.cs | 10 +- .../Http/Headers/ProductInfoHeaderParser.cs | 2 +- .../Http/Headers/ProductInfoHeaderValue.cs | 6 +- .../Http/Headers/RangeConditionHeaderValue.cs | 2 +- .../Net/Http/Headers/RangeHeaderValue.cs | 8 +- .../Net/Http/Headers/RangeItemHeaderValue.cs | 12 +- .../Http/Headers/RetryConditionHeaderValue.cs | 4 +- .../Headers/StringWithQualityHeaderValue.cs | 14 +- .../Http/Headers/TransferCodingHeaderValue.cs | 2 +- .../System/Net/Http/Headers/ViaHeaderValue.cs | 20 +- .../Net/Http/Headers/WarningHeaderValue.cs | 16 +- .../System/Net/Http/HttpResponseMessage.cs | 14 +- .../src/System/Net/Http/HttpRuleParser.cs | 2 +- .../src/System/Net/Http/MultipartContent.cs | 8 + .../AuthenticationHelper.NtAuth.cs | 74 +- .../AuthenticationHelper.NtAuth.tvOS.cs | 30 - .../ChunkedEncodingWriteStream.cs | 2 +- .../Http/SocketsHttpHandler/ConnectHelper.cs | 16 +- .../SocketsHttpHandler/Http2Connection.cs | 2 +- .../SocketsHttpHandler/Http3Connection.cs | 2 +- .../SocketsHttpHandler/Http3RequestStream.cs | 8 +- .../Http/SocketsHttpHandler/HttpConnection.cs | 22 +- .../SocketsHttpHandler/HttpConnectionPool.cs | 8 +- .../HttpConnectionSettings.cs | 10 - .../src/System/Net/Http/StreamContent.cs | 52 +- .../HttpClientAuthenticationTest.cs | 1 - .../HttpClientHandlerTest.AltSvc.cs | 20 +- .../HttpClientHandlerTest.Finalization.cs | 5 - .../HttpClientHandlerTest.Http3.cs | 115 +- ...lientHandlerTestBase.SocketsHttpHandler.cs | 44 +- .../HttpClientMiniStressTest.cs | 16 +- .../FunctionalTests/NtAuthTests.FakeServer.cs | 140 + .../FunctionalTests/NtAuthTests.Windows.cs | 21 +- .../ReadOnlyMemoryContentTest.cs | 237 +- .../ResponseStreamZeroByteReadTests.cs | 19 +- .../FunctionalTests/SocketsHttpHandlerTest.cs | 123 +- .../FunctionalTests/StreamContentTest.cs | 103 +- .../System.Net.Http.Functional.Tests.csproj | 114 +- .../tests/FunctionalTests/TelemetryTest.cs | 60 +- .../src/Resources/Strings.resx | 3 + .../Net/Managed/HttpResponseStream.Managed.cs | 2 +- .../WebSockets/HttpWebSocket.Managed.cs | 2 +- .../Net/Windows/HttpListener.Windows.cs | 17 +- .../Windows/HttpListenerContext.Windows.cs | 2 +- .../Net/Windows/HttpResponseStream.Windows.cs | 2 +- .../System.Net.Mail/ref/System.Net.Mail.cs | 6 +- .../src/Resources/Strings.resx | 3 + .../src/System/Net/Mail/MailAddress.cs | 12 +- .../src/System/Net/Mail/MailBnfHelper.cs | 23 +- .../src/System/Net/Mail/MailMessage.cs | 4 +- .../src/System/Net/Mail/MailPriority.cs | 2 +- .../src/System/Net/Mail/SmtpConnection.cs | 2 +- .../Net/Mail/SmtpFailedRecipientsException.cs | 2 +- .../src/System/Net/Mime/Base64Encoder.cs | 9 +- .../src/System/Net/Mime/QEncoder.cs | 2 +- .../System/Net/Mime/QuotedPrintableStream.cs | 2 +- .../src/System/Net/Mime/WriteStateInfoBase.cs | 6 +- .../BsdIPGlobalProperties.cs | 2 +- .../SystemIPGlobalProperties.cs | 12 +- .../SystemIPInterfaceProperties.cs | 10 +- .../SystemIPv4InterfaceProperties.cs | 11 +- .../SystemNetworkInterface.cs | 30 +- .../SystemUnicastIPAddressInformation.cs | 12 +- .../UnixIPGlobalProperties.cs | 2 +- .../Net/NetworkInformation/Ping.Windows.cs | 18 +- .../src/System/Net/Cookie.cs | 14 +- .../src/System/Net/IPAddress.cs | 6 +- .../System.Net.Quic/ref/System.Net.Quic.cs | 28 +- .../src/ExcludeApiList.PNSE.txt | 3 +- .../src/System.Net.Quic.csproj | 5 +- .../Implementations/Mock/MockConnection.cs | 484 --- .../Mock/MockImplementationProvider.cs | 26 - .../Quic/Implementations/Mock/MockListener.cs | 114 - .../Quic/Implementations/Mock/MockStream.cs | 338 -- .../MsQuic/Internal/MsQuicApi.cs | 37 +- .../Interop/SafeMsQuicConfigurationHandle.cs | 44 +- .../MsQuic/MsQuicConnection.cs | 30 +- .../MsQuic/MsQuicImplementationProvider.cs | 32 - .../Implementations/MsQuic/MsQuicListener.cs | 15 +- .../Implementations/MsQuic/MsQuicStream.cs | 162 +- .../Implementations/QuicConnectionProvider.cs | 37 - .../QuicImplementationProvider.cs | 18 - .../Implementations/QuicListenerProvider.cs | 17 - .../Implementations/QuicStreamProvider.cs | 62 - .../Net/Quic/QuicConnection.Unsupported.cs | 10 + .../src/System/Net/Quic/QuicConnection.cs | 40 +- ...QuicImplementationProviders.Unsupported.cs | 30 - .../Net/Quic/QuicImplementationProviders.cs | 12 - .../Net/Quic/QuicListener.Unsupported.cs | 10 + .../src/System/Net/Quic/QuicListener.cs | 36 +- .../src/System/Net/Quic/QuicStream.cs | 5 +- .../MsQuicCipherSuitesPolicyTests.cs | 13 +- .../MsQuicPlatformDetectionTests.cs | 7 +- .../tests/FunctionalTests/MsQuicTests.cs | 47 +- .../FunctionalTests/QuicConnectionTests.cs | 50 +- .../FunctionalTests/QuicListenerTests.cs | 36 +- ...icStreamConnectedStreamConformanceTests.cs | 42 +- .../tests/FunctionalTests/QuicStreamTests.cs | 38 +- .../tests/FunctionalTests/QuicTestBase.cs | 50 +- .../src/System/Net/FtpControlStream.cs | 9 +- .../src/System/Net/FtpDataStream.cs | 2 +- .../src/System/Net/HttpWebResponse.cs | 5 +- .../src/System/Net/TaskExtensions.cs | 5 +- .../ref/System.Net.Security.cs | 50 + .../src/Resources/Strings.resx | 3 + .../src/System.Net.Security.csproj | 31 +- .../src/System/Net/NTAuthentication.cs | 93 +- .../Net/Security/NegotiateAuthentication.cs | 326 ++ .../NegotiateAuthenticationClientOptions.cs | 41 + .../NegotiateAuthenticationServerOptions.cs | 36 + .../NegotiateAuthenticationStatusCode.cs | 63 + ...NegotiateStreamPal.PlatformNotSupported.cs | 6 +- .../Net/Security/NegotiateStreamPal.Unix.cs | 6 - .../Security/NegotiateStreamPal.Windows.cs | 211 +- .../System/Net/Security/SslSessionsCache.cs | 44 +- .../src/System/Net/Security/TlsFrameHelper.cs | 10 +- .../CertificateValidationRemoteServer.cs | 34 +- .../SslAuthenticationOptionsTest.cs | 1 + .../SslStreamNetworkStreamTest.cs | 2 +- .../tests/UnitTests/NTAuthenticationTests.cs | 88 - .../UnitTests/NegotiateAuthenticationTests.cs | 254 ++ .../System.Net.Security.Unit.Tests.csproj | 6 +- .../src/System/Net/Sockets/Socket.cs | 2 +- .../src/System/Net/Sockets/TCPListener.cs | 2 +- .../Net/WebSockets/WebSocketHandle.Managed.cs | 9 +- .../System/Net/WebSockets/ManagedWebSocket.cs | 2 +- .../Win32/SafeHandles/SafeFileHandle.Unix.cs | 51 +- .../SafeHandles/SafeFileHandle.Windows.cs | 4 +- .../src/Resources/Strings.resx | 47 +- .../System.Private.CoreLib.Shared.projitems | 22 +- .../System.Private.CoreLib/src/System/Byte.cs | 3 - .../System.Private.CoreLib/src/System/Char.cs | 31 - .../Collections/Generic/ArraySortHelper.cs | 4 +- .../Collections/Generic/ValueListBuilder.cs | 21 +- .../src/System/DateTime.Windows.cs | 2 +- .../src/System/Decimal.cs | 49 - .../src/System/DefaultBinder.cs | 7 +- .../System/Diagnostics/Tracing/EventSource.cs | 3 + .../Diagnostics/Tracing/RuntimeEventSource.cs | 4 + .../src/System/Double.cs | 798 +++- .../src/System/Empty.cs | 7 +- .../src/System/Environment.Unix.cs | 8 + .../src/System/Environment.Win32.cs | 27 +- .../src/System/Environment.Windows.cs | 28 + .../src/System/Environment.cs | 7 - .../src/System/Globalization/CultureData.cs | 52 +- .../src/System/Globalization/DateTimeParse.cs | 3 - .../System/Globalization/OrdinalCasing.Icu.cs | 2 +- .../System.Private.CoreLib/src/System/Half.cs | 73 +- .../src/System/IO/Directory.Unix.cs | 24 + .../src/System/IO/Directory.Windows.cs | 11 + .../src/System/IO/Directory.cs | 18 + .../src/System/IO/DirectoryInfo.cs | 2 +- .../Enumeration/FileSystemEnumerator.Unix.cs | 2 +- .../FileSystemEnumerator.Windows.cs | 2 +- .../IO/Enumeration/FileSystemEnumerator.cs | 2 +- .../src/System/IO/File.Unix.cs | 22 + .../src/System/IO/File.Windows.cs | 22 + .../src/System/IO/File.cs | 47 +- .../src/System/IO/FileInfo.cs | 2 +- .../src/System/IO/FileStatus.Unix.cs | 121 +- .../src/System/IO/FileStream.cs | 15 +- .../src/System/IO/FileStreamOptions.cs | 30 + .../src/System/IO/FileSystem.Unix.cs | 48 +- .../src/System/IO/FileSystem.cs | 14 + .../src/System/IO/FileSystemInfo.Unix.cs | 6 + .../src/System/IO/FileSystemInfo.Windows.cs | 8 + .../src/System/IO/FileSystemInfo.cs | 22 + .../src/System/IO/Path.cs | 10 +- .../src/System/IO/RandomAccess.Windows.cs | 28 +- .../AsyncWindowsFileStreamStrategy.cs | 4 +- .../IO/Strategies/FileStreamHelpers.Unix.cs | 4 +- .../Strategies/FileStreamHelpers.Windows.cs | 6 +- .../System/IO/Strategies/FileStreamHelpers.cs | 4 +- .../IO/Strategies/OSFileStreamStrategy.cs | 6 +- .../SyncWindowsFileStreamStrategy.cs | 4 +- .../IO/Strategies/UnixFileStreamStrategy.cs | 4 +- .../src/System/IO/UnixFileMode.cs | 65 + .../src/System/Int16.cs | 3 - .../src/System/Int32.cs | 3 - .../src/System/Int64.cs | 3 - .../src/System/IntPtr.cs | 3 - .../src/System/LocalAppContextSwitches.cs | 14 + .../System.Private.CoreLib/src/System/Math.cs | 42 +- .../src/System/MathF.cs | 8 +- .../src/System/Net/WebUtility.cs | 19 +- .../src/System/Numerics/IAdditionOperators.cs | 2 +- .../src/System/Numerics/IBinaryInteger.cs | 30 +- .../System/Numerics/IDecrementOperators.cs | 2 +- .../src/System/Numerics/IDivisionOperators.cs | 2 +- .../System/Numerics/IExponentialFunctions.cs | 8 +- .../src/System/Numerics/IFloatingPoint.cs | 12 +- .../System/Numerics/IFloatingPointIeee754.cs | 4 +- .../System/Numerics/IHyperbolicFunctions.cs | 2 +- .../System/Numerics/IIncrementOperators.cs | 2 +- .../System/Numerics/ILogarithmicFunctions.cs | 8 +- .../src/System/Numerics/IMultiplyOperators.cs | 2 +- .../src/System/Numerics/INumber.cs | 115 +- .../src/System/Numerics/INumberBase.cs | 6 +- .../src/System/Numerics/IPowerFunctions.cs | 2 +- .../src/System/Numerics/IRootFunctions.cs | 18 +- .../System/Numerics/ISubtractionOperators.cs | 2 +- .../Numerics/ITrigonometricFunctions.cs | 68 +- .../Numerics/IUnaryNegationOperators.cs | 2 +- .../src/System/Random.cs | 2 +- .../src/System/Reflection/AssemblyName.cs | 2 + .../System/Reflection/ConstructorInvoker.cs | 17 +- .../System/Reflection/Emit/TypeNameBuilder.cs | 11 +- .../System/Reflection/MethodInfo.Internal.cs | 7 +- .../Reflection/SignatureTypeExtensions.cs | 8 +- .../src/System/Resources/ResourceReader.cs | 2 + .../System/Resources/RuntimeResourceSet.cs | 3 + .../Runtime/InteropServices/Architecture.cs | 1 + .../Runtime/InteropServices/ComWrappers.cs | 2 +- .../System/Runtime/InteropServices/NFloat.cs | 101 +- .../InteropServices/RuntimeInformation.cs | 2 + .../src/System/SByte.cs | 3 - .../src/System/Single.cs | 607 ++- .../src/System/SpanHelpers.Byte.cs | 7 +- .../src/System/SpanHelpers.Char.cs | 7 +- .../src/System/SpanHelpers.cs | 19 +- .../src/System/Text/ASCIIUtility.cs | 4 +- .../src/System/Text/Latin1Encoding.cs | 37 +- ...ntSource.PortableThreadPool.NativeSinks.cs | 17 + ...veRuntimeEventSource.PortableThreadPool.cs | 39 + .../PortableThreadPool.ThreadCounts.cs | 51 +- .../PortableThreadPool.WorkerThread.cs | 30 +- .../System/Threading/PortableThreadPool.cs | 28 + .../Threading/ThreadInt64PersistentCounter.cs | 50 +- .../TimeZoneInfo.FullGlobalizationData.cs | 27 +- .../src/System/UInt128.cs | 24 +- .../src/System/UInt16.cs | 3 - .../src/System/UInt32.cs | 3 - .../src/System/UInt64.cs | 3 - .../src/System/UIntPtr.cs | 3 - .../src/System/UnitySerializationHolder.cs | 2 - .../Runtime/Serialization/AccessorBuilder.cs | 6 +- .../Serialization/ClassDataContract.cs | 31 +- .../Runtime/Serialization/CodeGenerator.cs | 9 +- .../Serialization/CollectionDataContract.cs | 23 +- .../Runtime/Serialization/DataContract.cs | 41 +- .../Serialization/DataContractSerializer.cs | 28 +- .../DataContractSurrogateCaller.cs | 12 +- .../Serialization/ExtensionDataReader.cs | 2 +- .../Json/DataContractJsonSerializer.cs | 29 +- .../Json/JsonFormatReaderGenerator.cs | 17 +- .../Json/JsonFormatWriterGenerator.cs | 15 +- .../Serialization/Json/JsonWriterDelegator.cs | 2 +- .../Serialization/Json/JsonXmlDataContract.cs | 4 +- .../Serialization/PrimitiveDataContract.cs | 4 + .../Runtime/Serialization/SchemaExporter.cs | 5 +- .../Runtime/Serialization/ScopedKnownTypes.cs | 8 +- .../Serialization/SurrogateDataContract.cs | 12 +- .../Runtime/Serialization/XmlDataContract.cs | 28 +- .../Serialization/XmlObjectSerializer.cs | 24 +- .../XmlObjectSerializerContext.cs | 20 +- .../XmlObjectSerializerReadContext.cs | 26 +- .../XmlObjectSerializerWriteContext.cs | 4 +- .../Serialization/XmlSerializableServices.cs | 8 +- .../Serialization/XmlWriterDelegator.cs | 8 +- .../src/System/Text/Base64Encoding.cs | 15 +- .../src/System/Text/BinHexEncoding.cs | 4 +- .../src/System/Xml/ArrayHelper.cs | 5 +- .../src/System/Xml/PrefixHandle.cs | 2 +- .../src/System/Xml/XmlBaseReader.cs | 4 +- .../src/System/Xml/XmlBaseWriter.cs | 4 +- .../src/System/Xml/XmlBinaryWriter.cs | 46 +- .../src/System/Xml/XmlDictionaryReader.cs | 2 +- .../src/System/Xml/XmlDictionaryWriter.cs | 2 +- .../src/System/Xml/XmlUTF8TextReader.cs | 44 +- .../src/System/Xml/XmlUTF8TextWriter.cs | 34 +- .../System.Private.Uri/src/System/Uri.cs | 5 +- .../System.Private.Uri/src/System/UriExt.cs | 8 +- .../src/System/Xml/Linq/XContainer.cs | 3 +- .../src/System/Xml/Linq/XElement.cs | 2 +- .../src/System/Xml/Linq/XNodeReader.cs | 2 +- .../src/System/Xml/Linq/XObject.cs | 10 +- .../src/System/Xml/XPath/XNodeNavigator.cs | 2 +- .../System.Private.Xml/src/Misc/HResults.cs | 2 - .../src/System/Xml/BinaryXml/SqlUtils.cs | 13 +- .../System/Xml/BinaryXml/XmlBinaryReader.cs | 18 +- .../Xml/Core/HtmlEncodedRawTextWriter.cs | 16 +- .../src/System/Xml/Core/QueryOutputWriter.cs | 15 +- .../System/Xml/Core/XmlAutoDetectWriter.cs | 17 +- .../Xml/Core/XmlEncodedRawTextWriter.cs | 36 +- .../Xml/Core/XmlEncodedRawTextWriterAsync.cs | 36 +- .../src/System/Xml/Core/XmlParserContext.cs | 24 +- .../src/System/Xml/Core/XmlTextReaderImpl.cs | 22 +- .../System/Xml/Core/XmlTextReaderImplAsync.cs | 11 +- .../src/System/Xml/Core/XmlTextWriter.cs | 2 +- .../System/Xml/Core/XmlWellFormedWriter.cs | 6 +- .../System/Xml/Core/XsdValidatingReader.cs | 4 +- .../Xml/Core/XsdValidatingReaderAsync.cs | 2 +- .../src/System/Xml/DiagnosticsSwitches.cs | 4 +- .../System/Xml/Dom/DocumentSchemaValidator.cs | 2 +- .../src/System/Xml/Dom/XPathNodeList.cs | 10 +- .../src/System/Xml/Dom/XmlDeclaration.cs | 2 +- .../src/System/Xml/Dom/XmlDocument.cs | 18 +- .../src/System/Xml/Dom/XmlElementList.cs | 10 +- .../src/System/Xml/Dom/XmlLoader.cs | 8 +- .../src/System/Xml/Dom/XmlName.cs | 8 +- .../src/System/Xml/Dom/XmlNode.cs | 3 +- .../src/System/Xml/Dom/XmlNodeReader.cs | 46 +- .../src/System/Xml/Dom/XmlNotation.cs | 6 +- .../src/System/Xml/Schema/Asttree.cs | 18 +- .../src/System/Xml/Schema/AutoValidator.cs | 6 +- .../src/System/Xml/Schema/BaseProcessor.cs | 13 +- .../src/System/Xml/Schema/BaseValidator.cs | 14 +- .../Xml/Schema/CompiledidEntityConstraint.cs | 12 +- .../src/System/Xml/Schema/ContentValidator.cs | 2 +- .../Xml/Schema/DataTypeImplementation.cs | 24 +- .../src/System/Xml/Schema/DtdParser.cs | 6 +- .../src/System/Xml/Schema/DtdValidator.cs | 22 +- .../src/System/Xml/Schema/FacetChecker.cs | 30 +- .../src/System/Xml/Schema/NamespaceList.cs | 8 +- .../src/System/Xml/Schema/Parser.cs | 16 +- .../src/System/Xml/Schema/ParserAsync.cs | 18 +- .../src/System/Xml/Schema/Preprocessor.cs | 57 +- .../src/System/Xml/Schema/SchemaAttDef.cs | 10 +- .../Xml/Schema/SchemaCollectionCompiler.cs | 41 +- .../Schema/SchemaCollectionpreProcessor.cs | 75 +- .../src/System/Xml/Schema/SchemaDeclBase.cs | 12 +- .../System/Xml/Schema/SchemaElementDecl.cs | 10 +- .../src/System/Xml/Schema/SchemaEntity.cs | 10 +- .../src/System/Xml/Schema/SchemaInfo.cs | 5 +- .../src/System/Xml/Schema/SchemaNames.cs | 6 +- .../Xml/Schema/SchemaNamespacemanager.cs | 10 +- .../src/System/Xml/Schema/SchemaNotation.cs | 6 +- .../System/Xml/Schema/SchemaSetCompiler.cs | 44 +- .../src/System/Xml/Schema/ValidationState.cs | 10 +- .../src/System/Xml/Schema/XdrBuilder.cs | 22 +- .../src/System/Xml/Schema/XdrValidator.cs | 18 +- .../src/System/Xml/Schema/XmlSchema.cs | 18 +- .../src/System/Xml/Schema/XmlSchemaAll.cs | 6 +- .../System/Xml/Schema/XmlSchemaAnnotated.cs | 6 +- .../System/Xml/Schema/XmlSchemaAnnotation.cs | 6 +- .../src/System/Xml/Schema/XmlSchemaAny.cs | 8 +- .../Xml/Schema/XmlSchemaAnyAttribute.cs | 8 +- .../src/System/Xml/Schema/XmlSchemaAppInfo.cs | 6 +- .../System/Xml/Schema/XmlSchemaAttribute.cs | 4 +- .../Xml/Schema/XmlSchemaAttributeGroup.cs | 6 +- .../Xml/Schema/XmlSchemaAttributeGroupref.cs | 10 +- .../src/System/Xml/Schema/XmlSchemaChoice.cs | 6 +- .../System/Xml/Schema/XmlSchemaCollection.cs | 27 +- .../Xml/Schema/XmlSchemaComplexContent.cs | 4 +- .../XmlSchemaComplexContentExtension.cs | 8 +- .../XmlSchemaComplexContentRestriction.cs | 8 +- .../src/System/Xml/Schema/XmlSchemaContent.cs | 6 +- .../Xml/Schema/XmlSchemaContentModel.cs | 4 +- .../Xml/Schema/XmlSchemaContentProcessing.cs | 4 +- .../Xml/Schema/XmlSchemaDerivationMethod.cs | 8 +- .../Xml/Schema/XmlSchemaDocumentation.cs | 10 +- .../src/System/Xml/Schema/XmlSchemaElement.cs | 6 +- .../System/Xml/Schema/XmlSchemaException.cs | 2 +- .../System/Xml/Schema/XmlSchemaExternal.cs | 8 +- .../src/System/Xml/Schema/XmlSchemaFacet.cs | 6 +- .../src/System/Xml/Schema/XmlSchemaForm.cs | 4 +- .../src/System/Xml/Schema/XmlSchemaGroup.cs | 4 +- .../System/Xml/Schema/XmlSchemaGroupBase.cs | 4 +- .../System/Xml/Schema/XmlSchemaGroupRef.cs | 6 +- .../Xml/Schema/XmlSchemaIdEntityConstraint.cs | 10 +- .../src/System/Xml/Schema/XmlSchemaImport.cs | 4 +- .../src/System/Xml/Schema/XmlSchemaInclude.cs | 4 +- .../System/Xml/Schema/XmlSchemaNotation.cs | 4 +- .../src/System/Xml/Schema/XmlSchemaObject.cs | 6 +- .../Xml/Schema/XmlSchemaObjectCollection.cs | 8 +- .../System/Xml/Schema/XmlSchemaObjectTable.cs | 8 +- .../System/Xml/Schema/XmlSchemaParticle.cs | 4 +- .../System/Xml/Schema/XmlSchemaRedefine.cs | 4 +- .../System/Xml/Schema/XmlSchemaSequence.cs | 4 +- .../src/System/Xml/Schema/XmlSchemaSet.cs | 13 +- .../Xml/Schema/XmlSchemaSimpleContent.cs | 4 +- .../Schema/XmlSchemaSimpleContentExtension.cs | 6 +- .../XmlSchemaSimpleContentRestriction.cs | 6 +- .../System/Xml/Schema/XmlSchemaSimpleType.cs | 6 +- .../Xml/Schema/XmlSchemaSimpleTypeList.cs | 6 +- .../Schema/XmlSchemaSimpleTypeRestriction.cs | 8 +- .../Xml/Schema/XmlSchemaSimpleTypeUnion.cs | 4 +- .../Xml/Schema/XmlSchemaSubstitutionGroup.cs | 6 +- .../src/System/Xml/Schema/XmlSchemaUse.cs | 4 +- .../System/Xml/Schema/XmlSchemaValidator.cs | 12 +- .../src/System/Xml/Schema/XsdDateTime.cs | 10 +- .../src/System/Xml/Schema/XsdDuration.cs | 7 +- .../src/System/Xml/Schema/XsdValidator.cs | 24 +- .../Serialization/CodeGenerationoptions.cs | 8 +- .../System/Xml/Serialization/CodeGenerator.cs | 9 +- .../Xml/Serialization/CodeIdentifiers.cs | 10 +- .../System/Xml/Serialization/Compilation.cs | 1 - .../DateTimeSerializationSection.cs | 12 +- .../Xml/Serialization/IXmlSerializable.cs | 8 +- .../Xml/Serialization/IXmlTextParser.cs | 4 +- .../System/Xml/Serialization/ImportContext.cs | 51 +- .../src/System/Xml/Serialization/Mappings.cs | 36 +- .../src/System/Xml/Serialization/Models.cs | 14 +- .../src/System/Xml/Serialization/NameTable.cs | 9 +- .../ReflectionXmlSerializationReader.cs | 4 - .../Xml/Serialization/SchemaImporter.cs | 22 +- .../Xml/Serialization/SchemaObjectWriter.cs | 41 +- .../Serialization/SoapAttributeAttribute.cs | 10 +- .../Serialization/SoapAttributeOverrides.cs | 14 +- .../Xml/Serialization/SoapElementAttribute.cs | 10 +- .../Xml/Serialization/SoapEnumAttribute.cs | 8 +- .../Xml/Serialization/SoapIgnoreAttribute.cs | 4 +- .../Xml/Serialization/SoapIncludeAttribute.cs | 2 - .../Serialization/SoapReflectionImporter.cs | 29 +- .../Xml/Serialization/SoapSchemamember.cs | 10 +- .../Xml/Serialization/SoapTypeAttribute.cs | 8 +- .../Xml/Serialization/TypeExtensions.cs | 8 +- .../src/System/Xml/Serialization/Types.cs | 31 +- .../Serialization/XmlAnyElementAttribute.cs | 2 +- .../Serialization/XmlAnyElementAttributes.cs | 10 +- .../Xml/Serialization/XmlArrayAttribute.cs | 2 +- .../Serialization/XmlArrayItemAttribute.cs | 4 +- .../Serialization/XmlArrayItemAttributes.cs | 10 +- .../Serialization/XmlAttributeAttribute.cs | 4 +- .../Serialization/XmlAttributeOverrides.cs | 16 +- .../System/Xml/Serialization/XmlAttributes.cs | 3 +- .../XmlChoiceIdentifierAttribute.cs | 2 +- .../Xml/Serialization/XmlElementAttribute.cs | 4 +- .../Xml/Serialization/XmlElementAttributes.cs | 10 +- .../System/Xml/Serialization/XmlMapping.cs | 2 +- .../Serialization/XmlReflectionImporter.cs | 77 +- .../Xml/Serialization/XmlReflectionMember.cs | 2 +- .../Xml/Serialization/XmlRootAttribute.cs | 6 +- .../Xml/Serialization/XmlSchemaExporter.cs | 47 +- .../Xml/Serialization/XmlSchemaImporter.cs | 93 +- .../XmlSchemaProviderAttribute.cs | 6 +- .../System/Xml/Serialization/XmlSchemas.cs | 42 +- .../XmlSerializationGeneratedCode.cs | 20 +- .../Serialization/XmlSerializationILGen.cs | 16 +- .../Serialization/XmlSerializationReader.cs | 70 +- .../XmlSerializationReaderILGen.cs | 68 +- .../Serialization/XmlSerializationWriter.cs | 107 +- .../XmlSerializationWriterILGen.cs | 53 +- .../System/Xml/Serialization/XmlSerializer.cs | 3 +- .../XmlSerializerAssemblyAttribute.cs | 4 +- .../Xml/Serialization/XmlSerializerFactory.cs | 26 +- .../Serialization/XmlSerializerNamespaces.cs | 18 +- .../XmlSerializerVersionAttribute.cs | 4 +- .../Xml/Serialization/XmlTextAttribute.cs | 2 +- .../Xml/Serialization/XmlTypeAttribute.cs | 2 +- .../Xml/Serialization/Xmlcustomformatter.cs | 24 +- .../src/System/Xml/Serialization/_Events.cs | 16 +- .../Xml/Serialization/indentedWriter.cs | 4 +- .../Xml/XPath/Internal/XPathMultyIterator.cs | 14 +- .../src/System/Xml/XPath/XPathException.cs | 2 +- .../src/System/Xml/XPath/XPathNavigator.cs | 2 +- .../src/System/Xml/XmlComplianceUtil.cs | 3 +- .../src/System/Xml/XmlConvert.cs | 7 +- .../src/System/Xml/XmlException.cs | 2 +- .../src/System/Xml/XmlNamespacemanager.cs | 2 +- .../src/System/Xml/XmlResolver.cs | 18 +- .../src/System/Xml/XmlSecureResolver.cs | 8 +- .../System/Xml/Xsl/IlGen/OptimizerPatterns.cs | 2 +- .../System/Xml/Xsl/IlGen/StaticDataManager.cs | 12 +- .../Xml/Xsl/IlGen/XmlILConstructAnalyzer.cs | 2 +- .../src/System/Xml/Xsl/IlGen/XmlILModule.cs | 3 +- .../src/System/Xml/Xsl/IlGen/XmlIlVisitor.cs | 3 +- .../src/System/Xml/Xsl/QIL/QilCloneVisitor.cs | 2 +- .../System/Xml/Xsl/QIL/QilReplaceVisitor.cs | 2 +- .../src/System/Xml/Xsl/QIL/QilXmlWriter.cs | 4 +- .../Xml/Xsl/Runtime/WhitespaceRuleReader.cs | 2 +- .../Xml/Xsl/Runtime/XmlAttributeCache.cs | 16 +- .../System/Xml/Xsl/Runtime/XmlQueryContext.cs | 18 +- .../src/System/Xml/Xsl/XPath/XPathBuilder.cs | 5 +- .../src/System/Xml/Xsl/XPath/XPathParser.cs | 46 +- .../System/Xml/Xsl/XPath/XPathQilFactory.cs | 3 +- .../src/System/Xml/Xsl/XPathConvert.cs | 2 +- .../System/Xml/Xsl/XmlQualifiedNameTest.cs | 2 +- .../src/System/Xml/Xsl/XmlQueryType.cs | 2 +- .../src/System/Xml/Xsl/XmlQueryTypeFactory.cs | 3 +- .../src/System/Xml/Xsl/XslException.cs | 2 +- .../Xml/Xsl/Xslt/CompilerScopeManager.cs | 3 +- .../src/System/Xml/Xsl/Xslt/Focus.cs | 3 +- .../System/Xml/Xsl/Xslt/InvokeGenerator.cs | 3 +- .../src/System/Xml/Xsl/Xslt/MatcherBuilder.cs | 3 +- .../src/System/Xml/Xsl/Xslt/QilGenerator.cs | 24 +- .../System/Xml/Xsl/Xslt/QilGeneratorEnv.cs | 5 +- .../Xml/Xsl/Xslt/XPathPatternBuilder.cs | 7 +- .../System/Xml/Xsl/Xslt/XPathPatternParser.cs | 5 +- .../src/System/Xml/Xsl/Xslt/XslAst.cs | 5 +- .../src/System/Xml/Xsl/Xslt/XslAstAnalyzer.cs | 7 +- .../src/System/Xml/Xsl/Xslt/XsltInput.cs | 2 +- .../src/System/Xml/Xsl/Xslt/XsltLoader.cs | 19 +- .../src/System/Xml/Xsl/Xslt/XsltQilFactory.cs | 3 +- .../src/System/Xml/Xsl/XsltOld/ActionFrame.cs | 16 +- .../Xml/Xsl/XsltOld/ApplyImportsAction.cs | 10 +- .../Xml/Xsl/XsltOld/ApplyTemplatesAction.cs | 12 +- .../System/Xml/Xsl/XsltOld/AttributeAction.cs | 12 +- .../Xml/Xsl/XsltOld/AttributeSetAction.cs | 12 +- .../src/System/Xml/Xsl/XsltOld/Avt.cs | 16 +- .../src/System/Xml/Xsl/XsltOld/AvtEvent.cs | 12 +- .../src/System/Xml/Xsl/XsltOld/BeginEvent.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/BuilderInfo.cs | 16 +- .../Xml/Xsl/XsltOld/CallTemplateAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/ChooseAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/CommentAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/CompiledAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/ContainerAction.cs | 24 +- .../src/System/Xml/Xsl/XsltOld/CopyAction.cs | 12 +- .../Xml/Xsl/XsltOld/CopyAttributesAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/CopyCodeAction.cs | 12 +- .../Xml/Xsl/XsltOld/CopyNodeSetAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/CopyOfAction.cs | 12 +- .../System/Xml/Xsl/XsltOld/DocumentScope.cs | 10 +- .../System/Xml/Xsl/XsltOld/ElementAction.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/EndEvent.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/Event.cs | 12 +- .../System/Xml/Xsl/XsltOld/ForEachAction.cs | 12 +- .../src/System/Xml/Xsl/XsltOld/HtmlProps.cs | 14 +- .../src/System/Xml/Xsl/XsltOld/IfAction.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/InputScope.cs | 12 +- .../Xml/Xsl/XsltOld/InputScopeManager.cs | 10 +- .../System/Xml/Xsl/XsltOld/MessageAction.cs | 14 +- .../System/Xml/Xsl/XsltOld/NameSpaceEvent.cs | 10 +- .../System/Xml/Xsl/XsltOld/NamespaceDecl.cs | 8 +- .../System/Xml/Xsl/XsltOld/NavigatorInput.cs | 14 +- .../System/Xml/Xsl/XsltOld/NumberAction.cs | 5 - .../src/System/Xml/Xsl/XsltOld/OutKeywords.cs | 8 +- .../src/System/Xml/Xsl/XsltOld/OutputScope.cs | 10 +- .../Xml/Xsl/XsltOld/OutputScopeManager.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/PrefixQName.cs | 10 +- .../XsltOld/ProcessingInstructionAction.cs | 8 +- .../src/System/Xml/Xsl/XsltOld/Processor.cs | 26 +- .../System/Xml/Xsl/XsltOld/RecordBuilder.cs | 4 +- .../src/System/Xml/Xsl/XsltOld/RootAction.cs | 22 +- .../Xml/Xsl/XsltOld/SequentialOutput.cs | 4 +- .../src/System/Xml/Xsl/XsltOld/SortAction.cs | 15 +- .../System/Xml/Xsl/XsltOld/StateMachine.cs | 10 +- .../System/Xml/Xsl/XsltOld/StringOutput.cs | 8 +- .../src/System/Xml/Xsl/XsltOld/Stylesheet.cs | 12 +- .../System/Xml/Xsl/XsltOld/TemplateAction.cs | 16 +- .../Xml/Xsl/XsltOld/TemplateBaseAction.cs | 14 +- .../Xml/Xsl/XsltOld/TemplateLookupAction.cs | 12 +- .../System/Xml/Xsl/XsltOld/TemplateManager.cs | 12 +- .../src/System/Xml/Xsl/XsltOld/TextAction.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/TextEvent.cs | 10 +- .../src/System/Xml/Xsl/XsltOld/TextOutput.cs | 12 +- .../src/System/Xml/Xsl/XsltOld/TheQuery.cs | 10 +- .../Xml/Xsl/XsltOld/UseAttributeSetsAction.cs | 12 +- .../System/Xml/Xsl/XsltOld/ValueOfAction.cs | 10 +- .../System/Xml/Xsl/XsltOld/WithParamAction.cs | 12 +- .../Xml/Xsl/XsltOld/XsltCompileContext.cs | 24 +- .../System/Xml/Xsl/XsltOld/XsltDebugger.cs | 4 +- .../src/System/Xml/Xsl/XsltOld/XsltOutput.cs | 14 +- .../Xml/Xsl/XsltOld/newinstructionaction.cs | 10 +- .../src/System/Xml/Xslt/XslTransform.cs | 16 +- .../TestData/xsltc/baseline/2-(1)cnt19.xsl | 9 - .../TestData/xsltc/baseline/bft 25.xsl | 9 - .../TestData/xsltc/baseline/bft1.txt | 1 - .../TestData/xsltc/baseline/bft1.xsl | 9 - .../TestData/xsltc/baseline/bft10.txt | 1 - .../TestData/xsltc/baseline/bft10a.xsl | 9 - .../TestData/xsltc/baseline/bft10b.xsl | 9 - .../TestData/xsltc/baseline/bft11.txt | 1 - .../TestData/xsltc/baseline/bft11a.xsl | 9 - .../TestData/xsltc/baseline/bft11b.xsl | 9 - .../TestData/xsltc/baseline/bft11c.xsl | 9 - .../TestData/xsltc/baseline/bft12.txt | 1 - .../TestData/xsltc/baseline/bft12a.xsl | 9 - .../TestData/xsltc/baseline/bft12b.xsl | 9 - .../TestData/xsltc/baseline/bft12c.xsl | 9 - .../TestData/xsltc/baseline/bft12d.xsl | 9 - .../TestData/xsltc/baseline/bft12e.xsl | 9 - .../TestData/xsltc/baseline/bft12f.xsl | 9 - .../TestData/xsltc/baseline/bft12g.xsl | 9 - .../TestData/xsltc/baseline/bft12h.xsl | 9 - .../TestData/xsltc/baseline/bft12i.xsl | 9 - .../TestData/xsltc/baseline/bft12j.xsl | 9 - .../TestData/xsltc/baseline/bft12k.xsl | 9 - .../TestData/xsltc/baseline/bft12l.xsl | 9 - .../TestData/xsltc/baseline/bft12m.xsl | 9 - .../TestData/xsltc/baseline/bft12n.xsl | 9 - .../TestData/xsltc/baseline/bft12o.xsl | 9 - .../TestData/xsltc/baseline/bft12p.xsl | 9 - .../TestData/xsltc/baseline/bft12q.xsl | 9 - .../TestData/xsltc/baseline/bft12r.xsl | 9 - .../TestData/xsltc/baseline/bft12s.xsl | 9 - .../TestData/xsltc/baseline/bft12t.xsl | 9 - .../TestData/xsltc/baseline/bft12u.xsl | 9 - .../TestData/xsltc/baseline/bft12v.xsl | 9 - .../TestData/xsltc/baseline/bft12w.xsl | 9 - .../TestData/xsltc/baseline/bft12x.xsl | 9 - .../TestData/xsltc/baseline/bft12y.xsl | 9 - .../TestData/xsltc/baseline/bft12z.xsl | 9 - .../TestData/xsltc/baseline/bft13.txt | 1 - .../TestData/xsltc/baseline/bft13.xsl | 9 - .../TestData/xsltc/baseline/bft14.txt | 1 - .../TestData/xsltc/baseline/bft14a.xsl | 9 - .../TestData/xsltc/baseline/bft15.txt | 6 - .../TestData/xsltc/baseline/bft15a.xsl | 11 - .../TestData/xsltc/baseline/bft15b.xsl | 11 - .../TestData/xsltc/baseline/bft16.txt | 5 - .../TestData/xsltc/baseline/bft16.xsl | 9 - .../TestData/xsltc/baseline/bft16.xslt | 9 - .../TestData/xsltc/baseline/bft17.txt | 1 - .../TestData/xsltc/baseline/bft18.txt | 6 - .../TestData/xsltc/baseline/bft18a.xsl | 11 - .../TestData/xsltc/baseline/bft18b.xsl | 11 - .../TestData/xsltc/baseline/bft19.txt | 1 - .../TestData/xsltc/baseline/bft19.xsl | 13 - .../TestData/xsltc/baseline/bft19a.xsl | 11 - .../TestData/xsltc/baseline/bft2.txt | 1 - .../TestData/xsltc/baseline/bft2.xsl | 9 - .../TestData/xsltc/baseline/bft20.txt | 1 - .../TestData/xsltc/baseline/bft20.xsl | 13 - .../TestData/xsltc/baseline/bft20a.xsl | 11 - .../TestData/xsltc/baseline/bft21.txt | 4 - .../TestData/xsltc/baseline/bft21.xsl | 18 - .../TestData/xsltc/baseline/bft21a.xml | 8 - .../TestData/xsltc/baseline/bft22.txt | 1 - .../TestData/xsltc/baseline/bft22.xsl | 9 - .../TestData/xsltc/baseline/bft23.txt | 1 - .../TestData/xsltc/baseline/bft23.xsl | 9 - .../TestData/xsltc/baseline/bft24.txt | 6 - .../TestData/xsltc/baseline/bft24a.xsl | 11 - .../TestData/xsltc/baseline/bft24b.xsl | 11 - .../TestData/xsltc/baseline/bft25.txt | 1 - .../TestData/xsltc/baseline/bft26.txt | 1 - .../TestData/xsltc/baseline/bft26.xsl | 9 - .../TestData/xsltc/baseline/bft27.txt | 5 - .../TestData/xsltc/baseline/bft28.txt | 5 - .../TestData/xsltc/baseline/bft29.txt | 30 - .../TestData/xsltc/baseline/bft3.txt | 1 - .../TestData/xsltc/baseline/bft3.xsl | 9 - .../TestData/xsltc/baseline/bft30.txt | 30 - .../TestData/xsltc/baseline/bft31.txt | 1 - .../TestData/xsltc/baseline/bft31.xsl | 9 - .../TestData/xsltc/baseline/bft32.txt | 5 - .../TestData/xsltc/baseline/bft33.txt | 1 - .../TestData/xsltc/baseline/bft34.txt | 5 - .../TestData/xsltc/baseline/bft35.txt | 5 - .../TestData/xsltc/baseline/bft36.txt | 5 - .../TestData/xsltc/baseline/bft37.txt | 5 - .../TestData/xsltc/baseline/bft38.txt | 5 - .../TestData/xsltc/baseline/bft4.xsl | 9 - .../TestData/xsltc/baseline/bft5.txt | 5 - .../TestData/xsltc/baseline/bft6.txt | 5 - .../TestData/xsltc/baseline/bft7.txt | 5 - .../TestData/xsltc/baseline/bft8.txt | 5 - .../TestData/xsltc/baseline/bft9.txt | 5 - .../TestData/xsltc/baseline/cct1.txt | 2 - .../TestData/xsltc/baseline/cnt1.txt | 1 - .../TestData/xsltc/baseline/cnt1.xsl | 9 - .../TestData/xsltc/baseline/cnt10.txt | 2 - .../TestData/xsltc/baseline/cnt10a.xsl | 9 - .../TestData/xsltc/baseline/cnt10b.xsl | 10 - .../TestData/xsltc/baseline/cnt11.txt | 1 - .../TestData/xsltc/baseline/cnt11a.xsl | 9 - .../TestData/xsltc/baseline/cnt11b.xsl | 10 - .../TestData/xsltc/baseline/cnt12.txt | 1 - .../TestData/xsltc/baseline/cnt12a.xsl | 9 - .../TestData/xsltc/baseline/cnt12b.xsl | 10 - .../TestData/xsltc/baseline/cnt13.txt | 5 - .../TestData/xsltc/baseline/cnt13.xsl | 9 - .../TestData/xsltc/baseline/cnt14.txt | 1 - .../TestData/xsltc/baseline/cnt14.xsl | 9 - .../TestData/xsltc/baseline/cnt14b.xsl | 9 - .../TestData/xsltc/baseline/cnt15.txt | 5 - .../TestData/xsltc/baseline/cnt15a.xsl | 9 - .../TestData/xsltc/baseline/cnt15b.xsl | 9 - .../TestData/xsltc/baseline/cnt16.txt | 1 - .../TestData/xsltc/baseline/cnt17.txt | 1 - .../TestData/xsltc/baseline/cnt18.txt | 5 - .../TestData/xsltc/baseline/cnt18.xsl | 9 - .../TestData/xsltc/baseline/cnt18.xslt | 9 - .../TestData/xsltc/baseline/cnt19.txt | 1 - .../TestData/xsltc/baseline/cnt2.txt | 1 - .../TestData/xsltc/baseline/cnt2.xsl | 9 - .../TestData/xsltc/baseline/cnt20.txt | 6 - .../TestData/xsltc/baseline/cnt20.xsl | 9 - .../TestData/xsltc/baseline/cnt21.txt | 1 - .../TestData/xsltc/baseline/cnt21.xsl | 9 - .../TestData/xsltc/baseline/cnt22.txt | 1 - .../TestData/xsltc/baseline/cnt22.xsl | 9 - .../TestData/xsltc/baseline/cnt23.txt | 1 - .../TestData/xsltc/baseline/cnt23.xsl | 9 - .../TestData/xsltc/baseline/cnt24.txt | 5 - .../TestData/xsltc/baseline/cnt25.txt | 1 - .../TestData/xsltc/baseline/cnt25a.xsl | 9 - .../TestData/xsltc/baseline/cnt25b.xsl | 10 - .../TestData/xsltc/baseline/cnt26.txt | 1 - .../TestData/xsltc/baseline/cnt26a.xsl | 9 - .../TestData/xsltc/baseline/cnt26b.xsl | 10 - .../TestData/xsltc/baseline/cnt27.txt | 1 - .../TestData/xsltc/baseline/cnt27a.xsl | 9 - .../TestData/xsltc/baseline/cnt27b.xsl | 10 - .../TestData/xsltc/baseline/cnt28.txt | 1 - .../TestData/xsltc/baseline/cnt28a.xsl | 9 - .../TestData/xsltc/baseline/cnt28b.xsl | 10 - .../TestData/xsltc/baseline/cnt29.txt | 1 - .../TestData/xsltc/baseline/cnt29a.xsl | 9 - .../TestData/xsltc/baseline/cnt29b.xsl | 10 - .../TestData/xsltc/baseline/cnt3.txt | 5 - .../TestData/xsltc/baseline/cnt3.xsl | 9 - .../TestData/xsltc/baseline/cnt4.txt | 1 - .../TestData/xsltc/baseline/cnt4.xsl | 9 - .../TestData/xsltc/baseline/cnt5.txt | 1 - .../TestData/xsltc/baseline/cnt5.xsl | 9 - .../TestData/xsltc/baseline/cnt6.txt | 1 - .../TestData/xsltc/baseline/cnt6.xsl | 9 - .../TestData/xsltc/baseline/cnt7.txt | 1 - .../TestData/xsltc/baseline/cnt7.xsl | 9 - .../TestData/xsltc/baseline/cnt8.txt | 1 - .../TestData/xsltc/baseline/cnt8a.xsl | 9 - .../TestData/xsltc/baseline/cnt8b.xsl | 10 - .../TestData/xsltc/baseline/cnt9.txt | 1 - .../TestData/xsltc/baseline/cnt9a.xsl | 9 - .../TestData/xsltc/baseline/cnt9b.xsl | 10 - .../TestData/xsltc/baseline/dft1.txt | 1 - .../TestData/xsltc/baseline/dft1.xsl | 9 - .../TestData/xsltc/baseline/dft10.txt | 1 - .../TestData/xsltc/baseline/dft10.xsl | 9 - .../TestData/xsltc/baseline/dft11.txt | 1 - .../TestData/xsltc/baseline/dft11.xsl | 9 - .../TestData/xsltc/baseline/dft12.txt | 1 - .../TestData/xsltc/baseline/dft12.xsl | 9 - .../TestData/xsltc/baseline/dft13.txt | 1 - .../TestData/xsltc/baseline/dft13.xsl | 9 - .../TestData/xsltc/baseline/dft14.txt | 1 - .../TestData/xsltc/baseline/dft14.xsl | 9 - .../TestData/xsltc/baseline/dft15.txt | 5 - .../TestData/xsltc/baseline/dft15.xsl | 9 - .../TestData/xsltc/baseline/dft16.txt | 5 - .../TestData/xsltc/baseline/dft16.xsl | 9 - .../TestData/xsltc/baseline/dft17.txt | 5 - .../TestData/xsltc/baseline/dft17.xsl | 9 - .../TestData/xsltc/baseline/dft18.txt | 5 - .../TestData/xsltc/baseline/dft18.xsl | 9 - .../TestData/xsltc/baseline/dft19.txt | 5 - .../TestData/xsltc/baseline/dft19.xsl | 9 - .../TestData/xsltc/baseline/dft2.txt | 1 - .../TestData/xsltc/baseline/dft2.xsl | 9 - .../TestData/xsltc/baseline/dft20.txt | 5 - .../TestData/xsltc/baseline/dft20.xsl | 9 - .../TestData/xsltc/baseline/dft21.txt | 5 - .../TestData/xsltc/baseline/dft21.xsl | 9 - .../TestData/xsltc/baseline/dft22.txt | 1 - .../TestData/xsltc/baseline/dft22.xsl | 9 - .../TestData/xsltc/baseline/dft23.txt | 1 - .../TestData/xsltc/baseline/dft23.xsl | 9 - .../TestData/xsltc/baseline/dft3.txt | 5 - .../TestData/xsltc/baseline/dft3.xsl | 9 - .../TestData/xsltc/baseline/dft4.txt | 5 - .../TestData/xsltc/baseline/dft4.xsl | 9 - .../TestData/xsltc/baseline/dft5.txt | 5 - .../TestData/xsltc/baseline/dft5.xsl | 9 - .../TestData/xsltc/baseline/dft6.txt | 1 - .../TestData/xsltc/baseline/dft6.xsl | 9 - .../TestData/xsltc/baseline/dft7.txt | 5 - .../TestData/xsltc/baseline/dft7.xsl | 9 - .../TestData/xsltc/baseline/dft8.txt | 1 - .../TestData/xsltc/baseline/dft8.xsl | 9 - .../TestData/xsltc/baseline/dft9.txt | 1 - .../TestData/xsltc/baseline/dft9.xsl | 9 - .../TestData/xsltc/baseline/fft10.txt | 5 - .../TestData/xsltc/baseline/fft10.xsl | 9 - .../TestData/xsltc/baseline/fft11.txt | 1 - .../TestData/xsltc/baseline/fft11.xsl | 9 - .../TestData/xsltc/baseline/fft12.txt | 5 - .../TestData/xsltc/baseline/fft12.xsl | 9 - .../TestData/xsltc/baseline/fft13.txt | 1 - .../TestData/xsltc/baseline/fft13.xsl | 9 - .../TestData/xsltc/baseline/fft14.txt | 5 - .../TestData/xsltc/baseline/fft14.xsl | 9 - .../TestData/xsltc/baseline/fft15.txt | 5 - .../TestData/xsltc/baseline/fft15.xsl | 9 - .../TestData/xsltc/baseline/fft16.txt | 1 - .../TestData/xsltc/baseline/fft16.xsl | 9 - .../TestData/xsltc/baseline/fft17.txt | 1 - .../TestData/xsltc/baseline/fft17.xsl | 9 - .../TestData/xsltc/baseline/fft18.txt | 1 - .../TestData/xsltc/baseline/fft18.xsl | 9 - .../TestData/xsltc/baseline/fft19.txt | 5 - .../TestData/xsltc/baseline/fft2.txt | 1 - .../TestData/xsltc/baseline/fft2.xsl | 9 - .../TestData/xsltc/baseline/fft20.txt | 5 - .../TestData/xsltc/baseline/fft21.txt | 5 - .../TestData/xsltc/baseline/fft3.txt | 1 - .../TestData/xsltc/baseline/fft3.xsl | 9 - .../TestData/xsltc/baseline/fft4.txt | 1 - .../TestData/xsltc/baseline/fft4.xsl | 9 - .../TestData/xsltc/baseline/fft5.txt | 7 - .../TestData/xsltc/baseline/fft6.txt | 1 - .../TestData/xsltc/baseline/fft6.xsl | 9 - .../TestData/xsltc/baseline/fft7.txt | 1 - .../TestData/xsltc/baseline/fft7a.xsl | 9 - .../TestData/xsltc/baseline/fft7b.xsl | 9 - .../TestData/xsltc/baseline/fft8.txt | 1 - .../TestData/xsltc/baseline/fft8a.xsl | 9 - .../TestData/xsltc/baseline/fft8b.xsl | 9 - .../TestData/xsltc/baseline/fft8c.xsl | 9 - .../TestData/xsltc/baseline/fft8d.xsl | 9 - .../TestData/xsltc/baseline/fft9.txt | 5 - .../TestData/xsltc/baseline/fft9.xsl | 9 - .../TestData/xsltc/baseline/help.txt | 30 - .../TestData/xsltc/baseline/identity.xsl | 7 - .../TestData/xsltc/baseline/infft10.txt | 1 - .../TestData/xsltc/baseline/infft10b.txt | 1 - .../TestData/xsltc/baseline/infft10c.txt | 1 - .../TestData/xsltc/baseline/infft11.txt | 1 - .../TestData/xsltc/baseline/infft11a.txt | 1 - .../TestData/xsltc/baseline/infft11b.txt | 1 - .../TestData/xsltc/baseline/infft12.txt | 1 - .../TestData/xsltc/baseline/infft12b.txt | 1 - .../TestData/xsltc/baseline/infft12c.txt | 1 - .../TestData/xsltc/baseline/infft13.txt | 1 - .../TestData/xsltc/baseline/infft13a.txt | 1 - .../TestData/xsltc/baseline/infft13b.txt | 1 - .../TestData/xsltc/baseline/infft14.txt | 1 - .../TestData/xsltc/baseline/infft14b.txt | 1 - .../TestData/xsltc/baseline/infft14c.txt | 1 - .../TestData/xsltc/baseline/infft15.txt | 1 - .../TestData/xsltc/baseline/infft15b.txt | 1 - .../TestData/xsltc/baseline/infft15c.txt | 1 - .../TestData/xsltc/baseline/infft16---.txt | Bin 20 -> 0 bytes .../TestData/xsltc/baseline/infft17.txt | 3 - .../TestData/xsltc/baseline/infft18.txt | 1 - .../TestData/xsltc/baseline/infft2.txt | Bin 18 -> 0 bytes .../TestData/xsltc/baseline/infft3.txt | 1 - .../TestData/xsltc/baseline/infft4.txt | 1 - .../TestData/xsltc/baseline/infft5.txt | 1 - .../TestData/xsltc/baseline/infft6.txt | 1 - .../TestData/xsltc/baseline/infft7a.txt | 1 - .../TestData/xsltc/baseline/infft7b.txt | 1 - .../TestData/xsltc/baseline/infft8a.txt | 1 - .../TestData/xsltc/baseline/infft8b.txt | 1 - .../TestData/xsltc/baseline/infft8c.txt | 1 - .../TestData/xsltc/baseline/infft9.txt | 1 - .../TestData/xsltc/baseline/mail.xml | 4 - .../TestData/xsltc/baseline/multith.txt | 1 - .../TestData/xsltc/baseline/ns1..cnt17.xsl | 9 - .../TestData/xsltc/baseline/ns1.ns2.cnt16.xsl | 9 - .../TestData/xsltc/baseline/oft1.txt | 1 - .../TestData/xsltc/baseline/oft1.xsl | 9 - .../TestData/xsltc/baseline/oft10.txt | 1 - .../TestData/xsltc/baseline/oft10.xsl | 9 - .../TestData/xsltc/baseline/oft11.txt | 5 - .../TestData/xsltc/baseline/oft11.xsl | 9 - .../TestData/xsltc/baseline/oft12.txt | 1 - .../TestData/xsltc/baseline/oft12.xsl | 9 - .../TestData/xsltc/baseline/oft13.txt | 1 - .../TestData/xsltc/baseline/oft13.xsl | 9 - .../TestData/xsltc/baseline/oft14.txt | 1 - .../TestData/xsltc/baseline/oft14.xsl | 9 - .../TestData/xsltc/baseline/oft15.txt | 1 - .../TestData/xsltc/baseline/oft15.xsl | 9 - .../TestData/xsltc/baseline/oft16.txt | 1 - .../TestData/xsltc/baseline/oft16.xsl | 9 - .../TestData/xsltc/baseline/oft17.txt | 1 - .../TestData/xsltc/baseline/oft17.xsl | 9 - .../TestData/xsltc/baseline/oft18.txt | 5 - .../TestData/xsltc/baseline/oft18.xsl | 9 - .../TestData/xsltc/baseline/oft19.txt | 5 - .../TestData/xsltc/baseline/oft19.xsl | 9 - .../TestData/xsltc/baseline/oft2.txt | 5 - .../TestData/xsltc/baseline/oft2.xsl | 9 - .../TestData/xsltc/baseline/oft20.txt | 5 - .../TestData/xsltc/baseline/oft20.xsl | 9 - .../TestData/xsltc/baseline/oft21.txt | 5 - .../TestData/xsltc/baseline/oft21.xsl | 9 - .../TestData/xsltc/baseline/oft22.txt | 1 - .../TestData/xsltc/baseline/oft22.xsl | 9 - .../TestData/xsltc/baseline/oft23.txt | 1 - .../TestData/xsltc/baseline/oft23.xsl | 9 - .../TestData/xsltc/baseline/oft25.txt | 1 - .../TestData/xsltc/baseline/oft25.xsl | 9 - .../TestData/xsltc/baseline/oft27.txt | 1 - .../TestData/xsltc/baseline/oft27.xsl | 9 - .../TestData/xsltc/baseline/oft28.txt | 1 - .../TestData/xsltc/baseline/oft28.xsl | 9 - .../TestData/xsltc/baseline/oft29.txt | 5 - .../TestData/xsltc/baseline/oft29.xsl | 9 - .../TestData/xsltc/baseline/oft3.txt | 1 - .../TestData/xsltc/baseline/oft3.xsl | 9 - .../TestData/xsltc/baseline/oft30.txt | 5 - .../TestData/xsltc/baseline/oft30.xsl | 9 - .../TestData/xsltc/baseline/oft31.txt | 5 - .../TestData/xsltc/baseline/oft31.xsl | 9 - .../TestData/xsltc/baseline/oft4.txt | 1 - .../TestData/xsltc/baseline/oft4a.xsl | 9 - .../TestData/xsltc/baseline/oft4b.xsl | 10 - .../TestData/xsltc/baseline/oft5.txt | 1 - .../TestData/xsltc/baseline/oft5a.xsl | 9 - .../TestData/xsltc/baseline/oft5b.xsl | 10 - .../TestData/xsltc/baseline/oft6.txt | 1 - .../TestData/xsltc/baseline/oft6a.xsl | 9 - .../TestData/xsltc/baseline/oft6b.xsl | 10 - .../TestData/xsltc/baseline/oft7.txt | 1 - .../TestData/xsltc/baseline/oft7.xsl | 9 - .../TestData/xsltc/baseline/oft8.txt | 1 - .../TestData/xsltc/baseline/oft8.xsl | 9 - .../TestData/xsltc/baseline/oft9.txt | 1 - .../TestData/xsltc/baseline/oft9.xsl | 9 - .../TestData/xsltc/baseline/pft1.txt | 1 - .../TestData/xsltc/baseline/pft1.xsl | 9 - .../TestData/xsltc/baseline/pft10.txt | 1 - .../TestData/xsltc/baseline/pft10.xsl | 9 - .../TestData/xsltc/baseline/pft11.txt | 5 - .../TestData/xsltc/baseline/pft11.xsl | 9 - .../TestData/xsltc/baseline/pft12.txt | 5 - .../TestData/xsltc/baseline/pft12.xsl | 9 - .../TestData/xsltc/baseline/pft13.txt | 5 - .../TestData/xsltc/baseline/pft13.xsl | 9 - .../TestData/xsltc/baseline/pft14.txt | 5 - .../TestData/xsltc/baseline/pft14.xsl | 9 - .../TestData/xsltc/baseline/pft15.txt | 5 - .../TestData/xsltc/baseline/pft15.xsl | 9 - .../TestData/xsltc/baseline/pft16.txt | 5 - .../TestData/xsltc/baseline/pft16.xsl | 9 - .../TestData/xsltc/baseline/pft17.txt | 1 - .../TestData/xsltc/baseline/pft17.xsl | 9 - .../TestData/xsltc/baseline/pft18.txt | 1 - .../TestData/xsltc/baseline/pft18.xsl | 9 - .../TestData/xsltc/baseline/pft19.txt | 1 - .../TestData/xsltc/baseline/pft19.xsl | 9 - .../TestData/xsltc/baseline/pft2.txt | 5 - .../TestData/xsltc/baseline/pft2.xsl | 9 - .../TestData/xsltc/baseline/pft20.txt | 1 - .../TestData/xsltc/baseline/pft20.xsl | 9 - .../TestData/xsltc/baseline/pft3.txt | 1 - .../TestData/xsltc/baseline/pft3.xsl | 9 - .../TestData/xsltc/baseline/pft4.txt | 5 - .../TestData/xsltc/baseline/pft4.xsl | 9 - .../TestData/xsltc/baseline/pft7.txt | 1 - .../TestData/xsltc/baseline/pft7.xsl | 9 - .../TestData/xsltc/baseline/pft8.dll | Bin 0 -> 4096 bytes .../TestData/xsltc/baseline/pft8.txt | 1 - .../TestData/xsltc/baseline/pft8.xsl | 9 - .../TestData/xsltc/baseline/pft9.txt | 1 - .../TestData/xsltc/baseline/pft9.xsl | 9 - .../TestData/xsltc/baseline/sft1.txt | 3 - .../TestData/xsltc/baseline/sft1.xml | 4 - .../TestData/xsltc/baseline/sft1.xsl | 13 - .../TestData/xsltc/baseline/sft10.txt | 2 - .../TestData/xsltc/baseline/sft10.xsl | 21 - .../TestData/xsltc/baseline/sft11.txt | 1 - .../TestData/xsltc/baseline/sft11.xsl | 7 - .../TestData/xsltc/baseline/sft13.txt | 1 - .../TestData/xsltc/baseline/sft13.xsl | 7 - .../TestData/xsltc/baseline/sft14.txt | 5 - .../TestData/xsltc/baseline/sft14.xsl | 9 - .../TestData/xsltc/baseline/sft15.txt | 5 - .../TestData/xsltc/baseline/sft15.xsl | 9 - .../TestData/xsltc/baseline/sft2.txt | 5 - .../TestData/xsltc/baseline/sft2.xsl | 13 - .../TestData/xsltc/baseline/sft27.txt | 3 - .../TestData/xsltc/baseline/sft27.xsl | 3 - .../TestData/xsltc/baseline/sft27a.xsl | 13 - .../TestData/xsltc/baseline/sft28.txt | 5 - .../TestData/xsltc/baseline/sft28.xsl | 3 - .../TestData/xsltc/baseline/sft28a.xsl | 13 - .../TestData/xsltc/baseline/sft29.txt | 2 - .../TestData/xsltc/baseline/sft29.xsl | 3 - .../TestData/xsltc/baseline/sft29a.xsl | 21 - .../TestData/xsltc/baseline/sft3.txt | 2 - .../TestData/xsltc/baseline/sft3.xsl | 21 - .../TestData/xsltc/baseline/sft30.txt | 5 - .../TestData/xsltc/baseline/sft30.xsl | 3 - .../TestData/xsltc/baseline/sft30a.xsl | 21 - .../TestData/xsltc/baseline/sft31.txt | 1 - .../TestData/xsltc/baseline/sft31.xsl | 3 - .../TestData/xsltc/baseline/sft31a.xsl | 7 - .../TestData/xsltc/baseline/sft32.txt | 5 - .../TestData/xsltc/baseline/sft32.xsl | 3 - .../TestData/xsltc/baseline/sft32a.xsl | 7 - .../TestData/xsltc/baseline/sft33.txt | 3 - .../TestData/xsltc/baseline/sft33.xsl | 3 - .../TestData/xsltc/baseline/sft33a.xsl | 13 - .../TestData/xsltc/baseline/sft34.txt | 5 - .../TestData/xsltc/baseline/sft34.xsl | 3 - .../TestData/xsltc/baseline/sft34a.xsl | 13 - .../TestData/xsltc/baseline/sft35.txt | 2 - .../TestData/xsltc/baseline/sft35.xsl | 3 - .../TestData/xsltc/baseline/sft35a.xsl | 21 - .../TestData/xsltc/baseline/sft36.dll | Bin 0 -> 5120 bytes .../TestData/xsltc/baseline/sft36.txt | 5 - .../TestData/xsltc/baseline/sft36.xsl | 3 - .../TestData/xsltc/baseline/sft36a.xsl | 21 - .../TestData/xsltc/baseline/sft37.txt | 1 - .../TestData/xsltc/baseline/sft37.xsl | 3 - .../TestData/xsltc/baseline/sft37a.xsl | 7 - .../TestData/xsltc/baseline/sft38.txt | 5 - .../TestData/xsltc/baseline/sft38.xsl | 3 - .../TestData/xsltc/baseline/sft38a.xsl | 7 - .../TestData/xsltc/baseline/sft4.txt | 5 - .../TestData/xsltc/baseline/sft4.xsl | 21 - .../TestData/xsltc/baseline/sft41.txt | 5 - .../TestData/xsltc/baseline/sft41.xsl | 9 - .../TestData/xsltc/baseline/sft42.txt | 5 - .../TestData/xsltc/baseline/sft42.xsl | 9 - .../TestData/xsltc/baseline/sft43.txt | 5 - .../TestData/xsltc/baseline/sft43.xsl | 9 - .../TestData/xsltc/baseline/sft44.txt | 5 - .../TestData/xsltc/baseline/sft44.xsl | 9 - .../TestData/xsltc/baseline/sft45.txt | 5 - .../TestData/xsltc/baseline/sft45.xsl | 9 - .../TestData/xsltc/baseline/sft46.txt | 5 - .../TestData/xsltc/baseline/sft46.xsl | 9 - .../TestData/xsltc/baseline/sft47.txt | 5 - .../TestData/xsltc/baseline/sft47.xsl | 9 - .../TestData/xsltc/baseline/sft48.txt | 5 - .../TestData/xsltc/baseline/sft48.xsl | 9 - .../TestData/xsltc/baseline/sft49.txt | 5 - .../TestData/xsltc/baseline/sft49.xsl | 9 - .../TestData/xsltc/baseline/sft5.txt | 1 - .../TestData/xsltc/baseline/sft5.xsl | 7 - .../TestData/xsltc/baseline/sft50.txt | 5 - .../TestData/xsltc/baseline/sft50.xsl | 9 - .../TestData/xsltc/baseline/sft6.txt | 5 - .../TestData/xsltc/baseline/sft6.xsl | 7 - .../TestData/xsltc/baseline/sft7.txt | 5 - .../TestData/xsltc/baseline/sft7.xsl | 9 - .../TestData/xsltc/baseline/sft8.txt | 1 - .../TestData/xsltc/baseline/sft8.xsl | 9 - .../TestData/xsltc/baseline/sft9.txt | 3 - .../TestData/xsltc/baseline/sft9.xsl | 13 - .../xsltc/precompiled/Scripting28.xsl | Bin 5996 -> 0 bytes .../TestData/xsltc/precompiled/sft1.xml | 4 - .../XsltCompiler/ApiTests/XsltcApiTest.cs | 52 - .../XsltcTestBasicFunctionality.cs | 45 - .../CommonScenarios/XsltcTestCaseBase.cs | 347 -- .../CommonScenarios/XsltcTestFile.cs | 76 - .../CommonScenarios/XsltcTestPlatform.cs | 103 - .../CommonScenarios/XsltcTestSettings.cs | 70 - .../tests/Xslt/XsltCompiler/Identity.xslt | 11 - .../Xslt/XsltCompiler/IdentityTransform.xslt | 11 - .../Xslt/XsltCompiler/TestStylesheet.xslt | 13 - .../tests/Xslt/XsltCompiler/XsltCommon.cs | 674 ---- .../XsltCompiler/XsltCompiler.Tests.csproj | 35 - .../tests/Xslt/XsltCompiler/XsltcModule.cs | 44 - .../Context/Virtual/VirtualMethodBase.cs | 26 +- ...alPropertyBase.FuncPropertyAccessorBase.cs | 4 +- .../VirtualPropertyBase.PropertyGetterBase.cs | 4 +- .../VirtualPropertyBase.PropertySetterBase.cs | 8 +- .../Context/Virtual/VirtualPropertyBase.cs | 34 +- .../System.Reflection.Emit.ILGeneration.sln | 169 +- .../System.Reflection.Emit.ILGeneration.cs | 2 +- .../tests/ILGenerator/Emit5Tests.cs | 305 ++ ....Reflection.Emit.ILGeneration.Tests.csproj | 1 + .../ModuleBuilder/ModuleBuilderDefineType.cs | 2 + .../src/System.Reflection.Metadata.csproj | 1 - .../MemoryBlocks/AbstractMemoryBlock.cs | 4 +- .../MemoryBlocks/ByteArrayMemoryBlock.cs | 2 +- .../MemoryBlocks/NativeHeapMemoryBlock.cs | 2 +- .../Internal/Utilities/BitArithmetic.cs | 4 +- .../Internal/Utilities/BlobUtilities.cs | 2 +- .../Internal/Utilities/EmptyArray.cs | 12 - .../ReadOnlyUnmanagedMemoryStream.cs | 2 +- .../Reflection/Metadata/Internal/BlobHeap.cs | 2 +- .../Metadata/MetadataReader.WinMD.cs | 10 +- .../Metadata/MetadataStringDecoder.cs | 2 +- .../PortableExecutable/PEBuilder.cs | 17 +- .../PEReader.EmbeddedPortablePdb.cs | 2 +- .../Reflection/PortableExecutable/PEReader.cs | 4 +- .../src/README.md | 40 + ...stem.Reflection.MetadataLoadContext.csproj | 8 +- .../src/System/Reflection/DefaultBinder.cs | 2 +- .../TypeLoading/General/AssemblyNameData.cs | 3 + .../Reflection/TypeLoading/Types/RoType.cs | 2 +- .../System.Reflection/System.Reflection.sln | 42 + .../tests/AssemblyNameTests.cs | 3 +- .../System.Reflection.InvokeEmit.Tests.csproj | 22 + .../InvokeEmit/runtimeconfig.template.json | 5 + ....Reflection.InvokeInterpreted.Tests.csproj | 22 + .../runtimeconfig.template.json | 5 + .../System.Reflection/tests/default.rd.xml | 4 + .../Runtime/Caching/CacheMemoryMonitor.cs | 2 +- .../src/System/Runtime/Caching/MemoryCache.cs | 8 +- .../tests/ILLink.Descriptors.xml | 3 + .../tests/System/AppDomainTests.cs | 2 - .../System/Environment.GetCommandLineArgs.cs | 33 + .../tests/System/Math.cs | 140 +- .../tests/System/MathF.cs | 82 + .../tests/CheckArchitectureTests.cs | 4 + .../Analyzers/CustomTypeMarshallerAnalyzer.cs | 46 +- .../Analyzers/CustomTypeMarshallerFixer.cs | 44 +- .../PInvokeStubCodeGenerator.cs | 14 +- .../GeneratedStatements.cs | 15 +- .../ManualTypeMarshallingHelper.V1.cs | 227 ++ .../ManualTypeMarshallingHelper.cs | 303 +- .../Marshalling/ArrayMarshaller.cs | 2 +- ...ributedMarshallingModelGeneratorFactory.cs | 148 +- .../CustomNativeTypeMarshallingGenerator.cs | 16 +- .../Marshalling/DelegateMarshaller.cs | 2 +- .../ICustomNativeTypeMarshallingStrategy.cs | 294 +- .../ICustomTypeMarshallingStrategy.cs | 135 + .../Marshalling/MarshallerHelpers.cs | 2 +- .../MarshallingGeneratorExtensions.cs | 2 +- .../MarshallingAttributeInfo.cs | 75 +- .../Resources/Strings.resx | 14 +- .../Resources/xlf/Strings.cs.xlf | 20 + .../Resources/xlf/Strings.de.xlf | 20 + .../Resources/xlf/Strings.es.xlf | 20 + .../Resources/xlf/Strings.fr.xlf | 20 + .../Resources/xlf/Strings.it.xlf | 20 + .../Resources/xlf/Strings.ja.xlf | 20 + .../Resources/xlf/Strings.ko.xlf | 20 + .../Resources/xlf/Strings.pl.xlf | 20 + .../Resources/xlf/Strings.pt-BR.xlf | 20 + .../Resources/xlf/Strings.ru.xlf | 20 + .../Resources/xlf/Strings.tr.xlf | 20 + .../Resources/xlf/Strings.zh-Hans.xlf | 20 + .../Resources/xlf/Strings.zh-Hant.xlf | 20 + .../StubCodeContext.cs | 19 +- .../SyntaxExtensions.cs | 11 +- .../TypeNames.cs | 3 +- .../ref/System.Runtime.InteropServices.cs | 11 +- .../CustomTypeMarshallersAttributeBase.cs | 21 + .../ManagedToUnmanagedMarshallersAttribute.cs | 32 + .../ArrayTests.cs | 8 +- .../CollectionTests.cs | 10 +- .../CustomMarshallingTests.V1.cs | 157 + .../CustomMarshallingTests.cs | 45 +- .../LibraryImportGenerator.Tests/SpanTests.cs | 10 +- .../CodeSnippets.cs | 81 + .../CompileFails.cs | 8 +- .../Compiles.cs | 27 +- .../Runtime/InteropServices/NFloatTests.cs | 650 +++ .../tests/TestAssets/NativeExports/Arrays.cs | 4 +- .../NativeExports/CustomMarshalling.cs | 16 +- .../TestAssets/SharedTypes/NonBlittable.V1.cs | 283 ++ .../TestAssets/SharedTypes/NonBlittable.cs | 292 +- .../tests/AssemblyLoadContextTest.cs | 2 - .../ref/System.Runtime.Numerics.cs | 26 +- .../src/System/Numerics/BigInteger.cs | 49 - .../Numerics/BigIntegerCalculator.DivRem.cs | 6 +- .../Numerics/BigIntegerCalculator.PowMod.cs | 16 +- .../src/System/Numerics/Complex.cs | 41 - .../Formatters/Binary/BinaryObjectReader.cs | 14 +- .../Formatters/Binary/BinaryObjectWriter.cs | 5 +- .../Formatters/Binary/BinaryParser.cs | 2 +- .../tests/DataContractSerializer.cs | 1 - .../System.Runtime/System.Runtime.sln | 42 + .../System.Runtime/ref/System.Runtime.cs | 217 +- .../tests/System.Runtime.Tests.csproj | 7 + .../tests/System/DoubleTests.cs | 326 ++ .../System.Runtime/tests/System/HalfTests.cs | 437 ++- ....Runtime.ReflectionInvokeEmit.Tests.csproj | 18 + .../InvokeEmit/runtimeconfig.template.json | 5 + ...e.ReflectionInvokeInterpreted.Tests.csproj | 18 + .../runtimeconfig.template.json | 5 + .../tests/System/Reflection/PointerTests.cs | 1 - .../tests/System/SingleTests.cs | 325 ++ .../tests/System/StringTests.cs | 17 + .../tests/System/TimeZoneInfoTests.cs | 2 + .../tests/System/Type/TypeTests.cs | 4 + .../System.Runtime/tests/default.rd.xml | 1 + .../src/System/Security/AccessControl/ACL.cs | 14 +- .../Security/AccessControl/Privilege.cs | 8 +- .../AccessControl/SecurityDescriptor.cs | 2 +- .../System.Security.Cryptography.Cose.csproj | 6 + .../Cryptography/Cose/CoseHeaderLabel.cs | 8 +- .../Cryptography/Cose/CoseHeaderMap.cs | 6 +- .../Cryptography/Cose/CoseSign1Message.cs | 2 +- .../tests/CoseHeaderLabelTests.cs | 36 +- .../Cryptography/Pal/AnyOS/ManagedPal.Asn.cs | 2 +- .../Windows/DecryptorPalWindows.Decrypt.cs | 2 +- .../Pal/Windows/PkcsPalWindows.Encrypt.cs | 2 +- .../src/Internal/Cryptography/PkcsHelpers.cs | 5 +- .../Cryptography/Pkcs/EnvelopedCms.cs | 2 +- .../DynamicRevocationTests.Android.cs | 2 +- ...Cryptography.X509Certificates.Tests.csproj | 14 - .../tests/X509StoreTests.Unix.cs | 2 +- .../Security/Cryptography/Xml/EncryptedXml.cs | 4 +- .../Security/Cryptography/Xml/Reference.cs | 3 +- .../Security/Cryptography/Xml/SignedXml.cs | 6 +- .../Cryptography/Xml/SignedXmlDebugLog.cs | 2 +- .../Cryptography/Xml/XmlDsigXPathTransform.cs | 2 +- .../ref/System.Security.Cryptography.cs | 6 - .../src/System.Security.Cryptography.csproj | 6 +- .../Cryptography/AppleCCCryptorLite.cs | 52 +- .../Security/Cryptography/AsnEncodedData.cs | 21 +- .../Cryptography/CapiHelper.Windows.cs | 4 +- .../Security/Cryptography/CryptoConfig.cs | 17 +- .../Security/Cryptography/CryptoStream.cs | 2 +- .../DESCryptoServiceProvider.Windows.cs | 4 +- .../Security/Cryptography/ECDsaCng.Key.cs | 6 +- .../Security/Cryptography/HMACCommon.cs | 16 +- .../HMACHashProvider.Browser.Managed.cs | 130 + .../HMACHashProvider.Browser.Native.cs | 99 + .../System/Security/Cryptography/HMACSHA1.cs | 1 - .../Security/Cryptography/HMACSHA256.cs | 1 - .../Security/Cryptography/HMACSHA384.cs | 1 - .../Security/Cryptography/HMACSHA512.cs | 1 - .../HashProviderDispenser.Browser.cs | 40 +- .../Security/Cryptography/IncrementalHash.cs | 2 - .../RC2CryptoServiceProvider.Windows.cs | 4 +- .../SHAHashProvider.Browser.Native.cs | 52 +- .../CertificatePal.Windows.cs | 14 +- .../X509Certificates/CertificatePolicy.cs | 6 +- ...inPal.Windows.GetChainStatusInformation.cs | 4 +- .../ManagedX509ExtensionProcessor.cs | 2 +- .../OpenSslCertificateAssetDownloader.cs | 3 +- .../OpenSslDirectoryBasedStoreProvider.cs | 95 +- .../X509Certificates/OpenSslPkcs12Reader.cs | 1 + .../RSAPkcs1X509SignatureGenerator.cs | 3 +- .../StorePal.Android.AndroidKeyStore.cs | 6 +- .../X509Certificates/StorePal.iOS.cs | 2 +- ...X509AuthorityInformationAccessExtension.cs | 8 +- .../X509BasicConstraintsExtension.cs | 2 +- .../X509EnhancedKeyUsageExtension.cs | 2 +- .../X509Certificates/X509Extension.cs | 12 + .../X509Certificates/X509KeyUsageExtension.cs | 2 +- .../X509SubjectKeyIdentifierExtension.cs | 6 +- .../tests/BlockSizeValueTests.cs | 2 +- .../tests/CryptoConfigTests.cs | 24 +- .../tests/HmacMD5Tests.cs | 10 + .../tests/HmacSha1Tests.cs | 11 +- .../tests/HmacSha256Tests.cs | 11 +- .../tests/HmacSha384Tests.cs | 11 +- .../tests/HmacSha512Tests.cs | 11 +- .../tests/HmacTests.cs | 1 - .../tests/IncrementalHashTests.cs | 29 +- .../tests/InvalidUsageTests.cs | 1 - .../tests/ReusabilityTests.cs | 24 +- .../tests/Rfc2202HmacTests.cs | 1 - .../tests/Rfc4231HmacTests.cs | 1 - .../System.Security.Cryptography.Tests.csproj | 6 +- .../tests/wasm.helix.targets | 35 + .../Permissions/PrincipalPermission.cs | 4 +- .../src/System/Security/Principal/SID.cs | 4 +- .../Syndication/Atom10FeedFormatter.cs | 6 +- .../Syndication/Rss20FeedFormatter.cs | 4 +- .../Syndication/SyndicationItem.cs | 2 +- .../src/System/ServiceProcess/ServiceBase.cs | 2 +- .../src/Internal/AsyncSerializedWorker.cs | 4 +- .../src/Internal/ObjectToken/ObjectToken.cs | 4 +- .../System.Speech/src/Internal/RBList.cs | 4 +- .../src/Internal/SrgsCompiler/BackEnd.cs | 6 +- .../Internal/SrgsParser/SrgsDocumentParser.cs | 2 +- .../src/Internal/SrgsParser/XmlParser.cs | 5 +- .../Synthesis/AudioFormatConverter.cs | 7 +- .../src/Internal/Synthesis/SSmlParser.cs | 4 +- .../src/Internal/Synthesis/VoiceSynthesis.cs | 4 +- .../System.Speech/src/Recognition/Grammar.cs | 6 +- .../src/Recognition/RecognizerBase.cs | 21 +- .../Recognition/SpeechRecognitionEngine.cs | 66 +- .../src/Recognition/SpeechRecognizer.cs | 66 +- .../SrgsGrammar/SrgsElementFactory.cs | 2 +- .../Recognition/SrgsGrammar/SrgsGrammar.cs | 2 +- .../src/Result/RecognizedPhrase.cs | 2 +- .../src/Synthesis/PromptBuilder.cs | 2 +- .../System.Speech/src/Synthesis/VoiceInfo.cs | 2 +- .../src/System/Text/DBCSCodePageEncoding.cs | 2 +- .../src/System/Text/EUCJPEncoding.cs | 12 +- .../src/System/Text/EncodingByteBuffer.cs | 3 +- .../src/System/Text/EncodingNLS.cs | 10 +- .../src/System/Text/ISO2022Encoding.cs | 14 +- .../src/System/Text/SBCSCodePageEncoding.cs | 2 +- .../System/Text/Encodings/Web/TextEncoder.cs | 4 +- .../gen/JsonSourceGenerator.Emitter.cs | 260 +- .../gen/JsonSourceGenerator.Parser.cs | 14 +- .../gen/PropertyGenerationSpec.cs | 7 + .../gen/Reflection/FieldInfoWrapper.cs | 5 + .../gen/Reflection/PropertyInfoWrapper.cs | 7 +- .../gen/TypeGenerationSpec.cs | 5 + .../System.Text.Json/ref/System.Text.Json.cs | 65 +- src/libraries/System.Text.Json/src/README.md | 11 + .../src/Resources/Strings.resx | 87 +- .../src/System.Text.Json.csproj | 30 +- .../src/System/Text/Json/BitStack.cs | 2 +- .../JsonPropertyDictionary.KeyCollection.cs | 10 +- .../JsonPropertyDictionary.ValueCollection.cs | 10 +- .../Text/Json/JsonPropertyDictionary.cs | 26 +- .../JsonPropertyInfoDictionaryValueList.cs | 206 + .../Json/Serialization/ConfigurationList.cs | 41 +- .../Converters/CastingConverter.cs | 70 + .../Collection/JsonCollectionConverter.cs | 6 +- .../Collection/JsonDictionaryConverter.cs | 2 +- .../Collection/StackOrQueueConverter.cs | 2 +- .../FSharp/FSharpTypeConverterFactory.cs | 4 +- .../JsonMetadataServicesConverter.cs | 12 +- .../Converters/Object/ObjectConverter.cs | 2 +- .../Object/ObjectDefaultConverter.cs | 20 +- ...ctWithParameterizedConstructorConverter.cs | 15 +- .../Value/NullableConverterFactory.cs | 2 +- .../Text/Json/Serialization/JsonConverter.cs | 19 +- .../Serialization/JsonConverterFactory.cs | 8 +- .../Json/Serialization/JsonConverterOfT.cs | 44 +- .../JsonSerializer.Read.HandlePropertyName.cs | 10 +- .../JsonSerializer.Read.Helpers.cs | 2 +- .../JsonSerializer.Read.Stream.cs | 174 +- .../JsonSerializer.Read.Utf8JsonReader.cs | 2 +- .../JsonSerializer.Write.Helpers.cs | 8 +- .../Serialization/JsonSerializerContext.cs | 22 +- .../JsonSerializerOptions.Caching.cs | 61 +- .../JsonSerializerOptions.Converters.cs | 275 +- .../Serialization/JsonSerializerOptions.cs | 180 +- .../Metadata/CustomJsonTypeInfoOfT.cs | 47 + .../DefaultJsonTypeInfoResolver.Converters.cs | 126 + .../Metadata/DefaultJsonTypeInfoResolver.cs | 138 + .../Metadata/IJsonTypeInfoResolver.cs | 24 + .../JsonMetadataServices.Converters.cs | 32 +- .../Metadata/JsonMetadataServices.cs | 27 +- .../Metadata/JsonParameterInfo.cs | 2 +- .../Metadata/JsonPropertyInfo.cs | 259 +- .../Metadata/JsonPropertyInfoOfT.cs | 357 +- .../Metadata/JsonTypeInfo.Cache.cs | 17 +- .../Serialization/Metadata/JsonTypeInfo.cs | 294 +- .../Metadata/JsonTypeInfoKind.cs | 28 + .../Serialization/Metadata/JsonTypeInfoOfT.cs | 54 +- .../Metadata/JsonTypeInfoResolver.cs | 67 + .../Serialization/Metadata/MemberAccessor.cs | 2 +- .../ReflectionEmitCachingMemberAccessor.cs | 2 +- .../Metadata/ReflectionEmitMemberAccessor.cs | 4 +- .../Metadata/ReflectionJsonTypeInfoOfT.cs | 70 +- .../Metadata/ReflectionMemberAccessor.cs | 4 +- .../Metadata/SourceGenJsonTypeInfoOfT.cs | 43 +- .../Json/Serialization/ReadBufferState.cs | 162 +- .../Text/Json/Serialization/ReadStack.cs | 10 +- .../Text/Json/Serialization/WriteStack.cs | 2 +- .../Json/Serialization/WriteStackFrame.cs | 6 +- .../src/System/Text/Json/ThrowHelper.Node.cs | 24 +- .../Text/Json/ThrowHelper.Serialization.cs | 69 +- .../src/System/Text/Json/ThrowHelper.cs | 12 + .../tests/Common/PropertyVisibilityTests.cs | 4 +- .../JsonSerializerContextTests.cs | 232 +- .../JsonSourceGeneratorTests.cs | 66 +- .../Serialization/CacheTests.cs | 1 + .../CustomConverterTests.cs | 8 +- .../JsonSerializerWrapper.Reflection.cs | 18 +- ...ltJsonTypeInfoResolverMultiContextTests.cs | 134 + ...nTypeInfoResolverTests.JsonPropertyInfo.cs | 1153 ++++++ ...tJsonTypeInfoResolverTests.JsonTypeInfo.cs | 830 ++++ .../DefaultJsonTypeInfoResolverTests.cs | 225 ++ .../JsonTypeInfoResolverTests.cs | 130 + .../MetadataTests/MetadataTests.Options.cs | 6 +- .../MetadataTests/TestResolver.cs | 22 + .../Serialization/OptionsTests.cs | 145 +- .../Stream.DeserializeAsyncEnumerable.cs | 17 +- .../TypeInfoResolverFunctionalTests.cs | 703 ++++ .../System.Text.Json.Tests.csproj | 8 + .../gen/Resources/xlf/Strings.cs.xlf | 4 +- .../gen/Resources/xlf/Strings.de.xlf | 4 +- .../gen/Resources/xlf/Strings.es.xlf | 4 +- .../gen/Resources/xlf/Strings.fr.xlf | 4 +- .../gen/Resources/xlf/Strings.it.xlf | 4 +- .../gen/Resources/xlf/Strings.ja.xlf | 4 +- .../gen/Resources/xlf/Strings.ko.xlf | 4 +- .../gen/Resources/xlf/Strings.pl.xlf | 4 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 4 +- .../gen/Resources/xlf/Strings.ru.xlf | 4 +- .../gen/Resources/xlf/Strings.tr.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 +- .../gen/UpgradeToRegexGeneratorAnalyzer.cs | 25 +- .../src/Resources/Strings.resx | 3 - .../Text/RegularExpressions/RegexNode.cs | 2 +- .../CSharpCodeFixVerifier`2.cs | 4 +- ...ystem.Text.RegularExpressions.Tests.csproj | 7 +- .../UpgradeToRegexGeneratorAnalyzerTests.cs | 32 +- .../tests/UnitTests/Stubs.cs | 15 - ....Text.RegularExpressions.Unit.Tests.csproj | 12 - .../ref/System.Threading.RateLimiting.cs | 70 +- .../src/System.Threading.RateLimiting.csproj | 2 + .../ChainedPartitionedRateLimiter.cs | 248 ++ .../DefaultPartitionedRateLimiter.cs | 276 ++ .../RateLimiting/PartitionedRateLimiter.cs | 218 +- .../RateLimiting/RateLimitPartition.T.cs | 5 +- .../RateLimiting/RateLimitPartition.cs | 57 + .../tests/ChainedLimiterTests.cs | 1085 ++++++ .../tests/Infrastructure/Utils.cs | 228 ++ .../tests/PartitionedRateLimiterTests.cs | 241 +- .../tests/RateLimiterPartitionTests.cs | 49 +- ...System.Threading.RateLimiting.Tests.csproj | 2 + .../src/Blocks/ActionBlock.cs | 2 +- .../src/Blocks/BatchBlock.cs | 4 +- .../src/Blocks/BroadcastBlock.cs | 2 +- .../src/Blocks/BufferBlock.cs | 4 +- .../src/Internal/SourceCore.cs | 7 +- .../src/Internal/TargetCore.cs | 2 +- .../src/System/Threading/Tasks/Parallel.cs | 4 +- .../tests/ThreadPoolTests.cs | 92 + .../src/System/Threading/Barrier.cs | 2 +- ...iCompatBaseline.NetCoreAppLatestStable.txt | 22 +- src/libraries/externals.csproj | 2 +- src/libraries/sendtohelix-wasm.targets | 143 +- src/libraries/tests.proj | 216 +- src/mono/CMakeLists.txt | 16 +- .../System.Private.CoreLib.csproj | 6 +- ...rce.PortableThreadPool.NativeSinks.Mono.cs | 4 + .../src/System/Exception.Mono.cs | 17 +- .../src/System/Reflection/CustomAttribute.cs | 4 +- .../Reflection/Emit/FieldBuilder.Mono.cs | 2 +- .../Reflection/Emit/ILGenerator.Mono.cs | 2 +- .../System/Reflection/Emit/MonoArrayMethod.cs | 4 +- .../Reflection/Metadata/MetadataUpdater.cs | 9 +- .../src/System/RuntimeType.Mono.cs | 7 +- .../src/System/String.Mono.cs | 4 +- src/mono/cmake/config.h.in | 4 - src/mono/mono.proj | 9 + src/mono/mono/arch/ppc/ppc-codegen.h | 9 +- src/mono/mono/component/debugger-agent.c | 10 +- src/mono/mono/component/debugger-protocol.h | 6 +- .../mono/component/debugger-state-machine.c | 2 +- src/mono/mono/component/event_pipe-stub.c | 20 + src/mono/mono/component/event_pipe.c | 1 + src/mono/mono/component/event_pipe.h | 9 + src/mono/mono/component/hot_reload-stub.c | 29 +- src/mono/mono/component/hot_reload.c | 151 +- src/mono/mono/component/hot_reload.h | 6 +- src/mono/mono/component/mini-wasm-debugger.c | 20 +- src/mono/mono/eglib/garray.c | 2 +- src/mono/mono/eglib/gdir-unix.c | 2 +- src/mono/mono/eglib/gfile.c | 2 +- src/mono/mono/eglib/giconv.c | 4 +- src/mono/mono/eglib/glib.h | 18 + src/mono/mono/eglib/gptrarray.c | 2 +- src/mono/mono/eventpipe/ep-rt-mono.c | 48 +- src/mono/mono/eventpipe/ep-rt-mono.h | 10 +- .../mono/eventpipe/gen-eventing-event-inc.lst | 1 + .../mono/metadata/assembly-load-context.c | 2 +- src/mono/mono/metadata/assembly.c | 3 +- src/mono/mono/metadata/class-init.c | 36 +- src/mono/mono/metadata/class.c | 9 +- src/mono/mono/metadata/custom-attrs.c | 21 +- src/mono/mono/metadata/debug-helpers.c | 15 +- src/mono/mono/metadata/debug-mono-ppdb.c | 22 +- src/mono/mono/metadata/dynamic-image.c | 3 +- src/mono/mono/metadata/dynamic-stream.c | 4 +- src/mono/mono/metadata/exception.c | 5 +- src/mono/mono/metadata/icall-decl.h | 2 + src/mono/mono/metadata/icall-def.h | 2 + src/mono/mono/metadata/icall-eventpipe.c | 33 +- src/mono/mono/metadata/icall.c | 36 +- src/mono/mono/metadata/image-internals.h | 4 +- src/mono/mono/metadata/image.c | 16 +- src/mono/mono/metadata/loader.c | 9 +- src/mono/mono/metadata/marshal.c | 33 +- src/mono/mono/metadata/memory-manager.c | 10 +- src/mono/mono/metadata/metadata-internals.h | 21 +- src/mono/mono/metadata/metadata-update.c | 16 +- src/mono/mono/metadata/metadata-update.h | 3 + src/mono/mono/metadata/metadata.c | 93 +- src/mono/mono/metadata/mono-basic-block.c | 9 +- src/mono/mono/metadata/mono-debug.c | 13 + src/mono/mono/metadata/mono-hash.c | 17 +- src/mono/mono/metadata/object-internals.h | 2 +- src/mono/mono/metadata/object.c | 17 +- src/mono/mono/metadata/reflection.c | 41 +- src/mono/mono/metadata/sre-encode.c | 3 +- src/mono/mono/metadata/threads.c | 86 +- src/mono/mono/mini/CMakeLists.txt | 21 + src/mono/mono/mini/abcremoval.c | 5 +- src/mono/mono/mini/alias-analysis.c | 9 +- src/mono/mono/mini/aot-compiler.c | 54 +- src/mono/mono/mini/branch-opts.c | 3 +- src/mono/mono/mini/cfgdump.c | 4 +- src/mono/mono/mini/debug-mini.c | 2 +- src/mono/mono/mini/decompose.c | 2 +- src/mono/mono/mini/driver.c | 25 +- src/mono/mono/mini/dwarfwriter.c | 2 +- src/mono/mono/mini/exceptions-amd64.c | 4 +- src/mono/mono/mini/exceptions-ppc.c | 9 + src/mono/mono/mini/genmdesc.py | 1 + src/mono/mono/mini/graph.c | 4 +- src/mono/mono/mini/helpers.c | 2 +- src/mono/mono/mini/interp/interp.c | 1 + src/mono/mono/mini/interp/transform.c | 4 +- src/mono/mono/mini/intrinsics.c | 5 + src/mono/mono/mini/ir-emit.h | 2 +- src/mono/mono/mini/linear-scan.c | 4 +- src/mono/mono/mini/lldb.c | 10 +- src/mono/mono/mini/mini-amd64-gsharedvt.c | 9 +- src/mono/mono/mini/mini-amd64.c | 60 +- src/mono/mono/mini/mini-arm.c | 58 +- src/mono/mono/mini/mini-arm64.c | 14 +- src/mono/mono/mini/mini-exceptions.c | 6 +- src/mono/mono/mini/mini-generic-sharing.c | 8 +- src/mono/mono/mini/mini-llvm.c | 20 +- src/mono/mono/mini/mini-ops.h | 2 +- src/mono/mono/mini/mini-ppc.c | 161 +- src/mono/mono/mini/mini-ppc.h | 20 +- src/mono/mono/mini/mini-profiler.c | 2 +- src/mono/mono/mini/mini-runtime.c | 16 +- src/mono/mono/mini/mini-unwind.h | 16 +- src/mono/mono/mini/mini-wasm.c | 14 +- src/mono/mono/mini/mini-wasm.h | 2 + src/mono/mono/mini/mini-x86.c | 4 +- src/mono/mono/mini/mini.c | 2 +- src/mono/mono/mini/mini.h | 11 +- src/mono/mono/mini/monovm.c | 2 +- src/mono/mono/mini/seq-points.c | 8 +- src/mono/mono/mini/tramp-ppc.c | 4 +- src/mono/mono/mini/unwind.c | 2 +- src/mono/mono/profiler/aot.c | 13 +- src/mono/mono/profiler/log.c | 10 +- src/mono/mono/utils/CMakeLists.txt | 6 +- src/mono/mono/utils/lock-free-alloc.c | 12 +- src/mono/mono/utils/mono-context.h | 6 +- src/mono/mono/utils/mono-flight-recorder.c | 6 +- src/mono/mono/utils/mono-poll.c | 6 +- src/mono/mono/utils/mono-rand.c | 2 +- src/mono/mono/utils/mono-sigcontext.h | 4 +- src/mono/mono/utils/mono-threads.c | 2 +- src/mono/mono/utils/monobitset.h | 6 +- src/mono/mono/utils/options-def.h | 3 +- src/mono/sample/HelloWorld/HelloWorld.csproj | 30 + src/mono/sample/HelloWorld/Makefile | 15 +- src/mono/wasm/build/WasmApp.Native.targets | 1 + src/mono/wasm/build/WasmApp.targets | 5 +- .../BrowserDebugHost/BrowserDebugHost.csproj | 1 + .../debugger/BrowserDebugProxy/DebugStore.cs | 74 +- .../BrowserDebugProxy/DevToolsHelper.cs | 3 +- .../Firefox/FirefoxExecutionContext.cs | 2 +- .../Firefox/FirefoxMonoProxy.cs | 4 +- .../MemberReferenceResolver.cs | 2 +- .../debugger/BrowserDebugProxy/MonoProxy.cs | 115 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 38 +- .../BrowserDebugProxy/ProxyOptions.cs | 4 +- src/mono/wasm/host/Options.cs | 4 +- src/mono/wasm/host/WasmAppHost.csproj | 1 + src/mono/wasm/runtime/CMakeLists.txt | 2 + src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js | 3 +- src/mono/wasm/runtime/crypto-worker.ts | 23 +- src/mono/wasm/runtime/driver.c | 18 + src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 3 +- src/mono/wasm/runtime/exports.ts | 9 +- src/mono/wasm/runtime/guarded-promise.ts | 34 + src/mono/wasm/runtime/js-to-cs.ts | 5 +- src/mono/wasm/runtime/package-lock.json | 2113 +++++++++- src/mono/wasm/runtime/package.json | 1 + src/mono/wasm/runtime/rollup.config.js | 53 +- src/mono/wasm/runtime/startup.ts | 7 +- src/mono/wasm/runtime/workers/README.md | 31 + .../{ => workers}/dotnet-crypto-worker.js | 48 +- src/mono/wasm/runtime/workers/tsconfig.json | 13 + src/mono/wasm/test-main.js | 25 +- src/mono/wasm/wasm.proj | 6 +- .../corehost/apphost/apphost.windows.cpp | 6 +- src/native/corehost/corehost.cpp | 4 +- src/native/corehost/deps_format.cpp | 2 +- src/native/corehost/dotnet/CMakeLists.txt | 3 +- src/native/corehost/dotnet/dotnet.ico | Bin 0 -> 45150 bytes src/native/corehost/dotnet/dotnet.rc | 1 + src/native/corehost/fxr/command_line.cpp | 58 +- src/native/corehost/fxr/command_line.h | 2 +- src/native/corehost/fxr/files.cmake | 2 + src/native/corehost/fxr/fx_muxer.cpp | 8 +- src/native/corehost/fxr/fx_resolver.cpp | 2 +- .../corehost/fxr/fx_resolver.messages.cpp | 4 +- src/native/corehost/fxr/install_info.cpp | 59 + src/native/corehost/fxr/install_info.h | 15 + src/native/corehost/fxr/sdk_resolver.cpp | 9 - src/native/corehost/fxr/sdk_resolver.h | 1 - src/native/corehost/fxr_resolver.cpp | 4 +- src/native/corehost/hostmisc/pal.h | 26 +- src/native/corehost/hostmisc/pal.unix.cpp | 77 +- src/native/corehost/hostmisc/pal.windows.cpp | 73 +- src/native/corehost/hostmisc/utils.cpp | 60 +- src/native/corehost/hostmisc/utils.h | 15 +- src/native/corehost/hostpolicy/args.cpp | 8 +- .../corehost/hostpolicy/deps_resolver.cpp | 2 +- src/native/corehost/hostpolicy/hostpolicy.cpp | 2 +- src/native/eventpipe/ds-ipc-pal-socket.c | 6 +- src/native/eventpipe/ep-event-source.c | 2 + src/native/external/libunwind.cmake | 40 + src/native/external/libunwind/CMakeLists.txt | 5 + .../external/libunwind/src/CMakeLists.txt | 33 + .../external/libunwind_extras/CMakeLists.txt | 2 + src/native/external/zlib-intel.cmake | 4 +- src/native/external/zlib.cmake | 4 +- src/native/libs/Common/pal_config.h.in | 1 - .../pal_localeStringData.c | 74 +- .../libs/System.Native/pal_networking.c | 3 +- .../System.Native/pal_runtimeinformation.c | 6 + .../System.Net.Security.Native/pal_gssapi.c | 30 - .../pal_x509chain.c | 6 +- .../pal_x509chain.h | 5 - .../entrypoints.c | 1 - .../pal_symmetric.c | 21 - .../pal_symmetric.h | 8 - .../pal_crypto_webworker.c | 27 +- .../pal_crypto_webworker.h | 11 +- src/native/libs/configure.cmake | 12 - .../metadata/details/assembly-functions.h | 1 + .../mono/metadata/details/image-functions.h | 4 +- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 99 +- .../BlazorWasmBuildPublishTests.cs | 9 +- .../Wasm.Build.Tests/BuildEnvironment.cs | 1 - .../Wasm.Build.Tests/MainWithArgsTests.cs | 2 - .../Wasm.Build.Tests/NativeLibraryTests.cs | 9 +- .../ReferenceNewAssemblyRebuildTest.cs | 1 - .../SatelliteAssembliesTests.cs | 47 +- .../Wasm.Build.Tests/WasmBuildAppTest.cs | 2 - .../Wasm.Build.Tests/WasmTemplateTests.cs | 1 + src/tests/Common/testenvironment.proj | 5 +- .../Interop/COM/ComWrappers/API/Program.cs | 4 + .../COM/ExtensionPoints/ExtensionPoints.cs | 82 + .../ExtensionPoints/ExtensionPoints.csproj | 10 + .../Interop/COM/ExtensionPoints/Interfaces.cs | 78 + .../COM/NETClients/Primitives/ErrorTests.cs | 27 +- .../COM/NETServer/ErrorMarshalTesting.cs | 9 + .../NativeClients/Primitives/ErrorTests.cpp | 39 + .../COM/NativeServer/ErrorMarshalTesting.h | 30 +- .../COM/ServerContracts/Server.Contracts.cs | 2 + .../COM/ServerContracts/Server.Contracts.h | 4 + src/tests/JIT/Directed/RVAInit/nested.ilproj | 2 + src/tests/JIT/Directed/RVAInit/simple.ilproj | 2 + .../StructABI/MisSizedStructs_ArmSplit.cs | 124 + .../StructABI/MisSizedStructs_ArmSplit.csproj | 13 + .../Directed/StructABI/TypeMismatchedArgs.cs | 67 + .../General/HwiOp/HwiValueNumbering.cs | 218 ++ .../General/HwiOp/HwiValueNumbering.csproj | 11 + src/tests/JIT/Intrinsics/BMI1Intrinsics.cs | 40 +- .../JitBlue/Runtime_61074/Runtime_61074.cs | 45 + .../Runtime_61074/Runtime_61074.csproj | 9 + .../JitBlue/Runtime_63905/Runtime_63905.cs | 46 + .../Runtime_63905/Runtime_63905.csproj | 9 + .../JitBlue/Runtime_65937/Runtime_65937.cs | 71 + .../Runtime_65937/Runtime_65937.csproj | 11 + .../JitBlue/Runtime_66089/Runtime_66089.cs | 78 + .../Runtime_66089/Runtime_66089.csproj | 10 + .../JitBlue/Runtime_68136/Runtime_68136.cs | 37 + .../Runtime_68136/Runtime_68136.csproj | 11 + .../JitBlue/Runtime_68568/Runtime_68568.il | 107 + .../Runtime_68568/Runtime_68568.ilproj | 12 + .../JitBlue/Runtime_70333/Runtime_70333.cs | 28 + .../Runtime_70333/Runtime_70333.csproj | 9 + .../JitBlue/Runtime_70466/Runtime_70466.cs | 38 + .../Runtime_70466/Runtime_70466.csproj | 9 + .../JitBlue/Runtime_70790/Runtime_70790.cs | 40 + .../Runtime_70790/Runtime_70790.csproj | 18 + .../JitBlue/Runtime_70824/Runtime_70824.cs | 48 + .../Runtime_70824/Runtime_70824.csproj | 10 + .../JitBlue/Runtime_70954/Runtime_70954.cs | 32 + .../Runtime_70954/Runtime_70954.csproj | 10 + src/tests/JIT/opt/Cloning/Runtime_70802.cs | 64 + .../JIT/opt/Cloning/Runtime_70802.csproj | 19 + src/tests/JIT/opt/Compares/compares.cs | 204 + src/tests/JIT/opt/Compares/compares.csproj | 12 + ...amondshape.cs => diamondshape.cs.template} | 0 ...cmethods.cs => genericmethods.cs.template} | 0 .../{methodimpl.cs => methodimpl.cs.template} | 0 ...ual_calls_to_instance_methods.cs.template} | 0 ...generics.cs => sharedgenerics.cs.template} | 0 .../simple/{simple.cs => simple.cs.template} | 0 .../{valuetypes.cs => valuetypes.cs.template} | 0 .../RegressionTests/GitHub_70385.cs.template | 36 + .../RegressionTests/GitHub_70385.il | 135 + .../RegressionTests/GitHub_70385.ilproj | 11 + .../exceptioninterop/CMakeLists.txt | 4 + .../exceptioninterop/ExceptionInterop.cs | 125 + .../exceptioninterop/ExceptionInterop.csproj | 10 + .../ExceptionInteropNative.cpp | 19 + .../ExceptionInterop_ro.csproj | 14 + .../InvalidOperations.csproj | 12 + .../invalid_operations/ManagedPointers.cs | 84 + src/tests/ilverify/ILVerificationTests.csproj | 2 +- src/tests/issues.targets | 22 +- .../nativeaot/SmokeTests/Dataflow/Dataflow.cs | 9 +- .../DeadCodeElimination.cs | 72 +- .../SmokeTests/DynamicGenerics/rd.xml | 21 + .../Preinitialization.csproj | 6 + .../SmokeTests/Reflection/Reflection.cs | 250 +- .../SmokeTests/Reflection/Reflection.csproj | 1 - ...nly.csproj => Reflection_FromUsage.csproj} | 7 +- .../profiler/native/gcprofiler/gcprofiler.cpp | 9 +- ...icrosoft.Diagnostics.NETCore.Client.csproj | 8 +- 2950 files changed, 57573 insertions(+), 33405 deletions(-) create mode 100644 docs/coding-guidelines/mono-code-guide.md create mode 100644 docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md create mode 100644 docs/design/security/unix-tmp.md create mode 100644 src/coreclr/debug/daccess/ppc64le/primitives.cpp create mode 100644 src/coreclr/debug/ee/ppc64le/dbghelpers.S create mode 100644 src/coreclr/debug/ee/ppc64le/primitives.cpp create mode 100644 src/coreclr/debug/shared/ppc64le/primitives.cpp delete mode 100644 src/coreclr/inc/contxt.h delete mode 100644 src/coreclr/inc/defaultallocator.h delete mode 100644 src/coreclr/inc/regex_base.h delete mode 100644 src/coreclr/inc/regex_util.h delete mode 100644 src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs rename src/coreclr/nativeaot/{System.Private.TypeLoader => System.Private.CoreLib}/src/Internal/Reflection/Core/AssemblyBinder.cs (92%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/Execution/FieldAccessor.cs (92%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/Execution/MethodInvoker.cs (81%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/Execution/ReflectionCoreExecution.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/Internal/Reflection/Core/ReflectionDomainSetup.cs (88%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/ActivatorImplementation.cs (94%) delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Helpers.cs rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs (94%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs (68%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/MemberTypeIndex.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs (93%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.NativeFormat.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs (86%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.Enumerator.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs (94%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/Dispenser.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/Assignability.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/BlockedRuntimeTypeNameGenerator.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/Dispensers.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/Helpers.NativeFormat.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/Helpers.cs (94%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/ListBuilder.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs (97%) rename src/coreclr/nativeaot/{System.Private.TypeLoader/src/Internal/Runtime/TypeLoader => System.Private.CoreLib/src/System/Reflection/Runtime/General}/MetadataReaderExtensions.cs (96%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/NamespaceChain.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs (93%) rename src/coreclr/nativeaot/{System.Private.TypeLoader => System.Private.CoreLib}/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs (99%) rename src/coreclr/nativeaot/{System.Private.TypeLoader => System.Private.CoreLib}/src/System/Reflection/Runtime/General/QHandles.cs (93%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/QSignatureTypeHandle.NativeFormat.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs (87%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/RuntimeTypeHandleKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/ThunkedApis.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/ToStringUtils.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeContext.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeForwardInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs (85%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeResolver.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/General/TypeUnifier.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs (94%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs (93%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/InvokerOptions.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs (86%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs (94%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/MethodInfos/VirtualRuntimeParameterInfoArray.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Modules/NativeFormat/NativeFormatRuntimeModule.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/Modules/RuntimeModule.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs (96%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs (96%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeTypeInfo.CoreGetDeclared.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeByRefTypeInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.UnificationKey.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs (95%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs (96%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs (98%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimePointerTypeInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs (96%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs (84%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs (90%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs (97%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeParsing/GetTypeOptions.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs (100%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeParsing/TypeName.cs (99%) rename src/coreclr/nativeaot/{System.Private.Reflection.Core => System.Private.CoreLib}/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs (99%) delete mode 100644 src/coreclr/nativeaot/System.Private.Reflection.Core/src/ILLink/ILLink.Substitutions.xml delete mode 100644 src/coreclr/nativeaot/System.Private.Reflection.Core/src/Resources/Strings.resx delete mode 100644 src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj delete mode 100644 src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs delete mode 100644 src/coreclr/pal/inc/rt/intsafe.h create mode 100644 src/coreclr/pal/inc/unixasmmacrosppc64le.inc create mode 100644 src/coreclr/pal/src/arch/ppc64le/asmconstants.h create mode 100644 src/coreclr/pal/src/arch/ppc64le/callsignalhandlerwrapper.S create mode 100644 src/coreclr/pal/src/arch/ppc64le/context2.S create mode 100644 src/coreclr/pal/src/arch/ppc64le/debugbreak.S create mode 100644 src/coreclr/pal/src/arch/ppc64le/exceptionhelper.S create mode 100644 src/coreclr/pal/src/arch/ppc64le/processor.cpp create mode 100644 src/coreclr/pal/src/arch/ppc64le/signalhandlerhelper.cpp create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitution.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectableFieldNode.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/AddedPseudoAttributeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseMemberAssertionAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/CreatedMemberAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DependencyRecordedAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DisplayNameAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/EnableLoggerAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectBodyModifiedAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExactlyResolvedDocumentationSignatureAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExceptionHandlersModifiedAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectGeneratedDocumentationSignatureAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectLocalsModifiedAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectResolvedDocumentationSignatureAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectUnresolvedDocumentationSignatureAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceOnMemberInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedLocalsSequenceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedNoWarningsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAllTypesAndMembersInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnFixedBufferTypeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseOnTypeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptDelegateCacheFieldAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventAddMethodAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventRemoveMethodAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptExportedTypeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptFixedBufferAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInitializerData.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceOnTypeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptModuleReferenceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferenceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferencesInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSecurityAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSymbolsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptTypeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/NoLinkedOutputAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ProducedBy.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyReference.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAttributeInAssembly.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedForwarderAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedInterfaceOnTypeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedPseudoAttributeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedResourceInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedSymbolsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedTypeInAssemblyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipKeptItemsValidationAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipPeVerifyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipRemainingErrorsValidationAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestCaseRequirementsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestRunCharacteristics.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowStringExtensions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowTypeExtensions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/PlatformAssemblies.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/DefineAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreDescriptorsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreLinkAttributesAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreSubstitutionsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/Il8nAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/KeepTypeForwarderOnlyAssembliesAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceDependencyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCSharpCompilerToUseAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileArgumentAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAsLibraryAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAssemblyNameAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileResourceAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkAttributesFile.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerActionAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerArgumentAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDefaultActionAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDescriptorFile.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerKeepDebugMembersAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkPublicAndFamilyAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkSymbolsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerResponseFileAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerSubstitutionFileAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerTrimModeAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripDescriptorsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripLinkAttributesAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripSubstitutionsAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/IntrinsicAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/RemoveAttributeInstancesAttribute.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetNestedTypeOnAllAnnotatedType.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeInfoDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/MemberTypesRelationships.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/TypeInfoAsTypeDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/UnsafeDataFlow.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Repro/Program.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/Mono.Linker.Tests.csproj create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestCase.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/BaseMetadataProvider.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/CompilerOptions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ExpectationsProvider.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/FormattingUtils.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptionsBuilder.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerTestCaseResult.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILInputCompiler.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/IgnoreTestException.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ManagedCompilationResult.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ObjectFactory.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/PathUtilities.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SourceAndDestinationPair.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseAssemblyResolver.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCollector.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompilationMetadataProvider.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestLogWriter.cs create mode 100644 src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs create mode 100644 src/coreclr/unwinder/ppc64le/unwinder_ppc64le.cpp delete mode 100644 src/coreclr/utilcode/iallocator.cpp delete mode 100644 src/coreclr/vm/ctxtcall.h delete mode 100644 src/coreclr/vm/dataimage.h create mode 100644 src/coreclr/vm/ppc64le/unixstubs.cpp delete mode 100644 src/coreclr/vm/sourceline.cpp delete mode 100644 src/coreclr/vm/sourceline.h delete mode 100644 src/coreclr/vm/stackcontents.h create mode 100644 src/libraries/Common/src/Interop/Browser/System.Security.Cryptography.Native.Browser/Interop.Sign.cs delete mode 100644 src/libraries/Common/src/Interop/Unix/System.Native/Interop.Permissions.cs rename src/libraries/Common/src/Interop/Windows/Kernel32/{Interop.VerSetConditionMask.cs => Interop.GetCommandLine.cs} (55%) delete mode 100644 src/libraries/Common/src/Interop/Windows/Kernel32/Interop.VerifyVersionExW.cs create mode 100644 src/libraries/Common/src/Interop/Windows/Shell32/Interop.CommandLineToArgv.cs delete mode 100644 src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.PlatformNotSupported.cs create mode 100644 src/libraries/Common/src/System/Console/ConsoleUtils.cs create mode 100644 src/libraries/Common/src/System/HashCodeRandomization.cs delete mode 100644 src/libraries/Common/src/System/Net/ContextFlagsAdapterPal.PlatformNotSupported.cs delete mode 100644 src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.PlatformNotSupported.cs create mode 100644 src/libraries/Common/tests/System/Net/Security/FakeNegotiateServer.cs rename src/libraries/{System.Net.Security/tests/UnitTests/Fakes => Common/tests/System/Net/Security}/FakeNtlmServer.cs (96%) create mode 100644 src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs create mode 100644 src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs create mode 100644 src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerQueueFullMode.cs create mode 100644 src/libraries/Microsoft.Extensions.Logging.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerProcessorTests.cs create mode 100644 src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxGlobalExtendedAttributesTarEntry.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarEntry/GnuTarEntry.Conversion.Tests.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarEntry/PaxTarEntry.Conversion.Tests.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarEntry/TarEntry.Conversion.Tests.Base.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarEntry/UstarTarEntry.Conversion.Tests.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarEntry/V7TarEntry.Conversion.Tests.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarReader/TarReader.ExtractToFile.Tests.Unix.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.GlobalExtendedAttributes.Tests.cs create mode 100644 src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.Base.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/Base/BaseGetSetUnixFileMode.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory_UnixFileMode.Unix.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory_UnixFileMode.Windows.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/DirectoryInfo/GetSetUnixFileMode.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/File/GetSetUnixFileMode.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/File/GetSetUnixFileMode_SafeFileHandle.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/FileInfo/GetSetUnixFileMode.cs create mode 100644 src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Delete.cs delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.tvOS.cs create mode 100644 src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockConnection.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockImplementationProvider.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockListener.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/Mock/MockStream.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicImplementationProvider.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/QuicConnectionProvider.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/QuicImplementationProvider.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/QuicListenerProvider.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/QuicStreamProvider.cs create mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.Unsupported.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/QuicImplementationProviders.Unsupported.cs delete mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/QuicImplementationProviders.cs create mode 100644 src/libraries/System.Net.Quic/src/System/Net/Quic/QuicListener.Unsupported.cs create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/NegotiateAuthentication.cs create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/NegotiateAuthenticationClientOptions.cs create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/NegotiateAuthenticationServerOptions.cs create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/NegotiateAuthenticationStatusCode.cs create mode 100644 src/libraries/System.Net.Security/tests/UnitTests/NegotiateAuthenticationTests.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/Directory.Unix.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/Directory.Windows.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/File.Unix.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/File.Windows.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/UnixFileMode.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/2-(1)cnt19.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft 25.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft10a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft10b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft11a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft11b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft11c.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12c.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12d.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12e.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12f.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12g.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12h.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12i.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12j.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12k.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12l.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12m.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12n.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12o.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12p.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12q.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12r.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12s.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12t.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12u.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12v.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12w.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12x.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12y.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft12z.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft14a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft15a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft15b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft16.xslt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft18a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft18b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft19.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft19a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft20.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft20a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft21.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft21.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft21a.xml delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft22.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft22.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft23.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft23.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft24.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft24a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft24b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft25.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft26.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft26.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft27.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft28.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft29.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft30.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft31.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft31.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft32.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft33.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft34.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft35.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft36.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft37.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft38.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/bft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cct1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt10a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt10b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt11a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt11b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt12a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt12b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt14b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt15a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt15b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt18.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt18.xslt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt20.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt21.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt21.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt22.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt22.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt23.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt23.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt24.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt25.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt25a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt25b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt26.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt26a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt26b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt27.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt27a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt27b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt28.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt28a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt28b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt29.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt29a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt29b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt5.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt6.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt7.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt8a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt8b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt9a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/cnt9b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft10.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft11.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft12.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft15.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft17.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft18.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft19.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft20.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft21.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft21.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft22.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft22.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft23.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft23.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft5.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft6.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft7.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft8.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/dft9.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft10.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft11.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft12.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft15.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft17.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft18.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft21.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft6.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft7a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft7b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft8a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft8b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft8c.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft8d.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/fft9.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/help.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/identity.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft10b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft10c.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft11a.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft11b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft12b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft12c.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft13a.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft13b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft14b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft14c.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft15b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft15c.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft16---.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft7a.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft7b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft8a.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft8b.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft8c.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/infft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/mail.xml delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/multith.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/ns1..cnt17.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/ns1.ns2.cnt16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft10.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft11.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft12.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft15.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft17.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft18.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft19.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft20.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft21.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft21.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft22.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft22.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft23.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft23.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft25.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft25.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft27.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft27.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft28.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft28.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft29.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft29.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft30.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft30.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft31.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft31.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft4a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft4b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft5a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft5b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft6a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft6b.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft7.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft8.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/oft9.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft10.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft11.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft12.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft12.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft15.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft16.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft16.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft17.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft17.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft18.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft18.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft19.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft19.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft20.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft20.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft7.xsl create mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft8.dll delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft8.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/pft9.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft1.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft1.xml delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft1.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft10.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft10.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft11.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft11.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft13.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft13.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft14.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft14.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft15.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft15.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft2.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft2.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft27.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft27.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft27a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft28.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft28.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft28a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft29.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft29.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft29a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft3.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft3.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft30.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft30.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft30a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft31.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft31.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft31a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft32.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft32.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft32a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft33.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft33.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft33a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft34.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft34.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft34a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft35.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft35.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft35a.xsl create mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft36.dll delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft36.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft36.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft36a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft37.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft37.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft37a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft38.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft38.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft38a.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft4.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft4.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft41.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft41.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft42.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft42.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft43.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft43.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft44.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft44.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft45.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft45.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft46.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft46.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft47.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft47.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft48.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft48.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft49.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft49.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft5.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft5.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft50.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft50.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft6.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft6.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft7.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft7.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft8.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft8.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft9.txt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/baseline/sft9.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/precompiled/Scripting28.xsl delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/TestFiles/TestData/xsltc/precompiled/sft1.xml delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/ApiTests/XsltcApiTest.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/CommonScenarios/XsltcTestBasicFunctionality.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/CommonScenarios/XsltcTestCaseBase.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/CommonScenarios/XsltcTestFile.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/CommonScenarios/XsltcTestPlatform.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/CommonScenarios/XsltcTestSettings.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/Identity.xslt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/IdentityTransform.xslt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/TestStylesheet.xslt delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/XsltCommon.cs delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/XsltCompiler.Tests.csproj delete mode 100644 src/libraries/System.Private.Xml/tests/Xslt/XsltCompiler/XsltcModule.cs create mode 100644 src/libraries/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit5Tests.cs delete mode 100644 src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EmptyArray.cs create mode 100644 src/libraries/System.Reflection.MetadataLoadContext/src/README.md create mode 100644 src/libraries/System.Reflection/tests/InvokeEmit/System.Reflection.InvokeEmit.Tests.csproj create mode 100644 src/libraries/System.Reflection/tests/InvokeEmit/runtimeconfig.template.json create mode 100644 src/libraries/System.Reflection/tests/InvokeInterpreted/System.Reflection.InvokeInterpreted.Tests.csproj create mode 100644 src/libraries/System.Reflection/tests/InvokeInterpreted/runtimeconfig.template.json create mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs create mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/InvokeEmit/System.Runtime.ReflectionInvokeEmit.Tests.csproj create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/InvokeEmit/runtimeconfig.template.json create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/InvokeInterpreted/System.Runtime.ReflectionInvokeInterpreted.Tests.csproj create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/InvokeInterpreted/runtimeconfig.template.json create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACHashProvider.Browser.Managed.cs create mode 100644 src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACHashProvider.Browser.Native.cs create mode 100644 src/libraries/System.Security.Cryptography/tests/wasm.helix.targets create mode 100644 src/libraries/System.Text.Json/src/README.md create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/JsonPropertyInfoDictionaryValueList.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/CastingConverter.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/CustomJsonTypeInfoOfT.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Converters.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/IJsonTypeInfoResolver.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoKind.cs create mode 100644 src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoResolver.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/DefaultJsonTypeInfoResolverMultiContextTests.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/DefaultJsonTypeInfoResolverTests.JsonPropertyInfo.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/DefaultJsonTypeInfoResolverTests.JsonTypeInfo.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/DefaultJsonTypeInfoResolverTests.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/JsonTypeInfoResolverTests.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/MetadataTests/TestResolver.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/TypeInfoResolverFunctionalTests.cs rename src/libraries/System.Text.RegularExpressions/tests/{UnitTests => FunctionalTests}/CSharpCodeFixVerifier`2.cs (96%) rename src/libraries/System.Text.RegularExpressions/tests/{UnitTests => FunctionalTests}/UpgradeToRegexGeneratorAnalyzerTests.cs (95%) create mode 100644 src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ChainedPartitionedRateLimiter.cs create mode 100644 src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/DefaultPartitionedRateLimiter.cs create mode 100644 src/libraries/System.Threading.RateLimiting/tests/ChainedLimiterTests.cs create mode 100644 src/libraries/System.Threading.RateLimiting/tests/Infrastructure/Utils.cs create mode 100644 src/mono/wasm/runtime/guarded-promise.ts create mode 100644 src/mono/wasm/runtime/workers/README.md rename src/mono/wasm/runtime/{ => workers}/dotnet-crypto-worker.js (83%) create mode 100644 src/mono/wasm/runtime/workers/tsconfig.json create mode 100644 src/native/corehost/dotnet/dotnet.ico create mode 100644 src/native/corehost/dotnet/dotnet.rc create mode 100644 src/native/corehost/fxr/install_info.cpp create mode 100644 src/native/corehost/fxr/install_info.h create mode 100644 src/tests/Interop/COM/ExtensionPoints/ExtensionPoints.cs create mode 100644 src/tests/Interop/COM/ExtensionPoints/ExtensionPoints.csproj create mode 100644 src/tests/Interop/COM/ExtensionPoints/Interfaces.cs create mode 100644 src/tests/JIT/Directed/StructABI/MisSizedStructs_ArmSplit.cs create mode 100644 src/tests/JIT/Directed/StructABI/MisSizedStructs_ArmSplit.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/General/HwiOp/HwiValueNumbering.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/General/HwiOp/HwiValueNumbering.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_61074/Runtime_61074.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_61074/Runtime_61074.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_63905/Runtime_63905.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_63905/Runtime_63905.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_65937/Runtime_65937.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_65937/Runtime_65937.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_66089/Runtime_66089.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_66089/Runtime_66089.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_68136/Runtime_68136.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_68136/Runtime_68136.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_68568/Runtime_68568.il create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_68568/Runtime_68568.ilproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70333/Runtime_70333.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70333/Runtime_70333.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70466/Runtime_70466.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70466/Runtime_70466.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70790/Runtime_70790.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70790/Runtime_70790.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70824/Runtime_70824.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70824/Runtime_70824.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70954/Runtime_70954.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_70954/Runtime_70954.csproj create mode 100644 src/tests/JIT/opt/Cloning/Runtime_70802.cs create mode 100644 src/tests/JIT/opt/Cloning/Runtime_70802.csproj create mode 100644 src/tests/JIT/opt/Compares/compares.cs create mode 100644 src/tests/JIT/opt/Compares/compares.csproj rename src/tests/Loader/classloader/DefaultInterfaceMethods/diamondshape/{diamondshape.cs => diamondshape.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/genericmethods/{genericmethods.cs => genericmethods.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/methodimpl/{methodimpl.cs => methodimpl.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/{non_virtual_calls_to_instance_methods.cs => non_virtual_calls_to_instance_methods.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/{sharedgenerics.cs => sharedgenerics.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/simple/{simple.cs => simple.cs.template} (100%) rename src/tests/Loader/classloader/DefaultInterfaceMethods/valuetypes/{valuetypes.cs => valuetypes.cs.template} (100%) create mode 100644 src/tests/Loader/classloader/StaticVirtualMethods/RegressionTests/GitHub_70385.cs.template create mode 100644 src/tests/Loader/classloader/StaticVirtualMethods/RegressionTests/GitHub_70385.il create mode 100644 src/tests/Loader/classloader/StaticVirtualMethods/RegressionTests/GitHub_70385.ilproj create mode 100644 src/tests/baseservices/exceptions/exceptioninterop/CMakeLists.txt create mode 100644 src/tests/baseservices/exceptions/exceptioninterop/ExceptionInterop.cs create mode 100644 src/tests/baseservices/exceptions/exceptioninterop/ExceptionInterop.csproj create mode 100644 src/tests/baseservices/exceptions/exceptioninterop/ExceptionInteropNative.cpp create mode 100644 src/tests/baseservices/exceptions/exceptioninterop/ExceptionInterop_ro.csproj create mode 100644 src/tests/baseservices/invalid_operations/InvalidOperations.csproj create mode 100644 src/tests/baseservices/invalid_operations/ManagedPointers.cs rename src/tests/nativeaot/SmokeTests/Reflection/{Reflection_ReflectedOnly.csproj => Reflection_FromUsage.csproj} (84%) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 76d5359f980ba..da9f3bf10c05b 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.22305.1", + "version": "1.0.0-prerelease.22320.3", "commands": [ "xharness" ] diff --git a/Directory.Build.props b/Directory.Build.props index 45dabffc314c7..4f9312803f030 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,6 +35,7 @@ arm64 loongarch64 s390x + ppc64le wasm x64 x64 diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index 307da15465cec..83f7a5ab45da1 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -1099,3 +1099,40 @@ 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 code from The Practice of Programming +------------------------------- + +Copyright (C) 1999 Lucent Technologies + +Excerpted from 'The Practice of Programming +by Brian W. Kernighan and Rob Pike + +You may use this code for any purpose, as long as you leave the copyright notice and book citation attached. + +License notice for amd/aocl-libm-ose +------------------------------- + +Copyright (C) 2008-2020 Advanced Micro Devices, Inc. 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. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +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. diff --git a/docs/coding-guidelines/clr-code-guide.md b/docs/coding-guidelines/clr-code-guide.md index 85987de5b047e..88a4c3a06c74f 100644 --- a/docs/coding-guidelines/clr-code-guide.md +++ b/docs/coding-guidelines/clr-code-guide.md @@ -437,7 +437,7 @@ A GC_NOTRIGGER function cannot: [1] With one exception: GCX_COOP (which effects a preemp->coop->preemp roundtrip) is permitted. The rationale is that GCX_COOP becomes a NOP if the thread was cooperative to begin with so it's safe to allow this (and necessary to avoid some awkward code in our product.) -**Note that for GC to be truly prevented, the caller must also ensure that the thread is in cooperative mode.** Otherwise, all the precautions above are in vain since any other thread can start a GC at any time. Given that, you might be wondering why cooperative mode is not part of the definition of GC_NOTRIGGER. In fact, there is a third thread state called GC_FORBID which is exactly that: GC_TRIGGERS plus forced cooperative mode. As its name implies, GC_FORBID _guarantees_ that no GC will occur on any thread. +**Note that for GC to be truly prevented, the caller must also ensure that the thread is in cooperative mode.** Otherwise, all the precautions above are in vain since any other thread can start a GC at any time. Given that, you might be wondering why cooperative mode is not part of the definition of GC_NOTRIGGER. In fact, there is a third thread state called GC_FORBID which is exactly that: GC_NOTRIGGER plus forced cooperative mode. As its name implies, GC_FORBID _guarantees_ that no GC will occur on any thread. Why do we use GC_NOTRIGGERS rather than GC_FORBID? Because forcing every function to choose between GC_TRIGGERS and GC_FORBID is too inflexible given that some callers don't actually care about GC. Consider a simple class member function that returns the value of a field. How should it be declared? If you choose GC_TRIGGERS, then the function cannot be legally called from a GC_NOTRIGGER function even though this is perfectly safe. If you choose GC_FORBID, then every caller must switch to cooperative mode to invoke the function just to prevent an assert. Thus, GC_NOTRIGGER was created as a middle ground and has become far more pervasive and useful than GC_FORBID. Callers who actually need GC stopped will have put themselves in cooperative mode anyway and in those cases, GC_NOTRIGGER actually becomes GC_FORBID. Callers who don't care can just call the function and not worry about modes. diff --git a/docs/coding-guidelines/mono-code-guide.md b/docs/coding-guidelines/mono-code-guide.md new file mode 100644 index 0000000000000..8433df9f7b655 --- /dev/null +++ b/docs/coding-guidelines/mono-code-guide.md @@ -0,0 +1,253 @@ +# Mono code guidelines + +This document is meant to capture guidelines for contributing code to +the [src/mono/mono/](../../src/mono/mono), +[src/native/public/mono](../../src/native/public/mono) areas of the +dotnet/runtime repo. + +In general this guide does not apply to: + +1. Shared native code in [src/native](../../src/native) +2. The Mono-specific C# code in [src/mono](../../src/mono) in System.Private.CoreLib or elsewhere + +## Code style + +Mono is written in C. + +We follow the [Mono Coding guidelines](https://www.mono-project.com/community/contributing/coding-guidelines/) for the C code - in particular: + +* tabs, not spaces +* space between a function name and the open parenthesis +* braces on the same line as `if`, `for`, `while` etc + +## Naming + +Mono reserves the following prefixes for symbols: `mono_`, `monovm_`, `m_`, `monoeg_` (used to remap [`eglib`](../../src/mono/mono/eglib) +functions which in source code have a `g_` prefix). + +All non-`static` symbols should use one of these prefixes. We generally use `mono_` for most +functions. `m_` is used for some inline accessor functions and macros. `g_` (`mono_eg_`) is used +for `eglib` functions. + +Types in a single C file can use any name. Types in a header should use a `Mono` (or sometimes +`mono_`) prefix. + +Public API symbols and types *must* be prefixed. + +For types Mono generally uses `typedef struct _MonoWhatever { ... } MonoWhatever`. Opaque types may +define `typedef struct _MonoWhatever MonoWhatever` in a client header and define `struct +_MonoWhatever {...}` in an implementation header. Occasionally we break `#include` cycles by adding +forward declarations for some types. + +## Macros + +Mono derives from an autotools-style project so we generally write `HOST_XYZ` for the machine on +which the runtime is executing (as opposed to the machine on which the runtime was compiled), and +`TARGET_XYZ` for the machine that will be targeted by the JIT and AOT compilers. In the case of AOT +compilation host and target might be different: the host might be Windows, and the target might be +Browser WebAssembly, for example. + +Macros generally use a `MONO_` prefix. Macros in public API headers *must* use the prefix. + +## Types + +Prefer the standard C sized types `int32_t`, `intptr_t`, etc over the eglib types `gint32`, `gsize` etc. + +One exception is `gboolean` is prefered over C `bool`. + +There are actually three boolean types to keep in mind: + +* `gboolean` used internally in the runtime +* `MonoBoolean` used as an interop type with C# bool in internal calls +* `mono_bool` used by the public C API - generally new code shouldn't use it except when adding a new public API function. + +## Utility and platform abstraction functions + +Mono generally tries to fill in POSIX-like abstractions on platforms that lack them (for example, Windows). +This is in contrast to the CoreCLR PAL which generally tries to add Windows API abstractions on top +of POSIX. + +If an existing `eglib` utility function is available, it should be used. New ones can be added. + +Other platform specific code is in `src/mono/utils` + +## Directory dependencies + +For the code in `src/mono/mono`: + +* `eglib` should not depend on other code from `src/mono` + +* `utils` can depend on `eglib` and 3rd party code from `src/native/external` + +* `sgen` depends on `eglib` and `utils` + +* `metadata` depends on all of the above (but note that some Boehm-GC files in this directory should not depend on `sgen`) + +* `mini` depends on all of the above + +* `mini/interp` depends on all of the above + +* `components` can use functions from all of the above provided they're marked with + `MONO_COMPONENT_API`, see [../design/mono/components.md](../design/mono/components.md) + +The main distinction between `metadata` and `utils` is that utils code should not assume that it is +part of an executing .NET runtime - anything that loads types, creates objects, etc does not belong +in utils but in metadata. + +The `mini` directory contains execution engines. If the execution engine has to provide some +functionality to `metadata` it generally does so by installing some callback that is invoked by +`metadata`. For example, `mini` knows how to unwind exceptions and perform stack walks - while +`metadata` decides *when* to unwind or perform a stackwalk. To coordinate, `metadata` exposes an +API to install hooks and `mini` provides the implementations. + +## Error handling + +New code should prefer to use the `MonoError` functions. + +* A non-public-API function should take a `MonoError *` argument. +* In case of an error the function should call one of the `mono_error_set_` functions from [../../src/mono/mono/utils/mono-error-internals.h](../../src/mono/mono/utils/mono-error-internals.h) +* Inside the runtime check whether there was an error by calling `is_ok (error)`, `mono_error_assert_ok (error)`, `goto_if_nok` or `return_if_nok`/`return_val_if_nok` +* If there is an error and you're handling it, call `mono_error_cleanup (error)` to dispose of the resources. +* `MonoError*` is generally one-shot: after it's been cleaned up it needs to be re-inited with `mono_error_init_reuse`, but this is discouraged. +* Instead if you intend to deal with an error, use `ERROR_DECL (local_error)` then call the + possibly-failing function and pass it `local_error`, then call `mono_error_assert_ok + (local_error)` if it "can't fail" or `mono_error_cleanup (local_error)` if you want to ignore the + failure. + +## Managed Exceptions + +New code should generally not deal with `MonoException*`, use `MonoError*` instead. + +New code should avoid using `mono_error_set_pending_exception` - it affects a thread-local flag in +a way that is not obvious to the caller of your function and may trample existing in-flight +exceptions and make your code fail in unexpected ways. + +There are two circumstances when you might need to call `mono_error_set_pending_exception`: + +1. You're working with a public Mono API that sets a pending exception +2. You're implementing an icall, but can't use `HANDLES()` (see the [internal calls](#internal-calls) section below) + +## Internal calls + +Prefer P/Invokes or QCalls over internal calls. That is, if your function only takes arguments that +are not managed objects, and does not need to interact with the runtime, it is better to define it +outside the runtime. + +Internal calls generally have at least one argument that is a managed object, or may throw a managed exception. + +Internal calls are declared in [`icall-def.h`](../../src/mono/mono/metadata/icall-def.h) See the comment in the header for details. + +There are two styles of internal calls: `NOHANDLES` and `HANDLES`. (This is a simplification as there +are also JIT internal calls added by the execution engines) + +The difference is that `HANDLES` icalls receive references to managed objects wrapped in a handle +that attempts to keep the object alive for the duration of the internal call even if the thread +blocks or is suspended, while `NOHANDLES` functions don't. Additionally `HANDLES` functions get a +`MonoError*` argument from the managed-to-native interop layer that will be converted to a managed +exception when the function returns. `NOHANDLES` functions generally have to call +`mono_error_set_pending_exception` themselves. + +## Suspend Safety + +See [Cooperative Suspend at mono-project.com](https://www.mono-project.com/docs/advanced/runtime/docs/coop-suspend/) and the [mono thread state machine design document](../design/mono/mono-thread-state-machine.md) + +In general runtime functions that may be called from the public Mono API should call +`MONO_ENTER_GC_UNSAFE`/`MONO_EXIT_GC_UNSAFE` if they call any other runtime API. Internal calls are +already in GC Unsafe on entry, but QCalls and P/Invokes aren't. + +When calling a blocking native API, wrap the call in `MONO_ENTER_GC_SAFE`/`MONO_EXIT_GC_SAFE`. + +Prefer `mono_coop_` synchronization primitives (`MonoCoopMutex`, `MonoCoopCond`, +`MonoCoopSemaphore`, etc) over `mono_os_` primitives (`mono_mutex_t`, `mono_cond_t`). The former +will automatically go into GC Safe mode before doing operations that may block. The latter should +only be used for low-level leaf locks that may need to be shared with non-runtime code. You're +responsible for switching to GC Safe mode when doing blocking operations in that case. + +## GC Memory Safety + +We have explored many different policies on how to safely access managed memory from the runtime. The existing code is not uniform. + +This is the current policy (but check with a team member as this document may need to be updated): + +1. It is never ok to access a managed object from GC Safe code. +2. Mono's GC scans the managed heap precisely. Mono does not allow heap objects to contain pointers into the interior of other managed obejcts. +3. Mono's GC scans the native stack conservatively: any value that looks like a pointer into the GC + heap, will cause the target object to be pinned and not collected. Interior pointers from the + stack into the middle of a managed object are allowed and will pin the object. + +In general one of the following should be used to ensure that an object is kept alive, particularly +across a call back into managed from native, or across a call that may trigger a GC (effectively +nearly any runtime internal API, due to assembly loading potentially triggering managed callbacks): + +* The object is pinned in managed code using `fixed` (common with strings) and the native code gets a `gunichar2*` +* a `ref` local is passed into native code and the native code gets a `MonoObject * volatile *` (the `volatile` is important) +* a `Span` is passed into native code and the native code gets a `MonoSpanOfObjects*` +* an icall is declared with `HANDLES()` and a `MonoObjectHandle` (or a more specific type such as `MonoReflectionTypeHandle` is passed in). +* a GCHandle is passed in + +Generally only functions on the boundary between managed and native should use one of the above +mechanisms (that is, it's enough that an object is pinned once). Callees can take a `MonoObject*` +argument and assume that it was pinned by the caller. + +In cases where an object is created in native code, it should be kept alive: + +1. By assigning into a `MonoObject * volatile *` (ie: use `out` or `ref` arguments in C#) +2. By creating a local handle using `MONO_HANDLE_NEW` or `MONO_HANDLE_PIN` (the function should then use `HANDLE_FUNCTION_ENTER`/`HANDLE_FUNCTION_RETURN` to set up and tear down a handle frame) +3. By creating a GCHandle +4. By assigning to a field of another managed object + +In all cases, if there is any intervening internal API call or a call to managed code, the object +must be kept alive before the call using one of the above methods. + +### Write barriers + +When writing a managed object to a field of another managed object, use one of the +`mono_gc_wbarrier_` functions (for example, `mono_gc_wbarrier_generic_store`). It is ok to call the write +barrier functions if the destination is not in the managed heap (in which case they will just do a normal write) + +## Assertions + +Mono code should use `g_assert`, `mono_error_assert_ok`, `g_assertf`, `g_assert_not_reached` etc. + +Unlike CoreCLR, Mono assertions are always included in the runtime - both in Debug and in Release builds. + +New code should try not to rely on the side-effects of assert conditions. (That is, one day we may want +to turn off assertions in Release builds.) + +## Mono Public API + +Mono maintains a public API for projects that embed the Mono runtime in order to provide the ability +to execute .NET code in the context of another application or framework. The current Mono API is +`mono-2.0`. We strive to maintain binary ABI and API stability for our embedders. + +The public API headers are defined in +[`../../src/native/public/mono`](../../src/native/public/mono). Great care should be taken when +modifying any of the functions declared in these headers. In particular breaking the ABI by +removing these functions or changing their arguments is not allowed. Semantic changes should be +avoided, or implemented in a way that is least disruptive to embedders (for example the runtime does +not support multiple appdomains anymore, but `mono_domain_get` continues to work). + +### Hidden API functions + +In practice certain functions have been tagged with `MONO_API` even if they are not declared in the +public headers. These symbols have been used by projects that embed Mono despite not being in the +public headers. They should be treated with the same care as the real public API. + +### Unstable API functions + +Functions declared in `mono-private-unstable.h` headers do not need to maintain API/ABI stability. +They are generally new APIs that have been added since .NET 5 but that have not been stabilized yet. + +As a matter of courtesy, notify the .NET macios and .NET Android teams if changing the behavior of these functions. + +### WASM + +The WASM and WASI runtimes in [`src/mono/wasm/runtime`](../../src/mono/wasm/runtime) and +`src/mono/wasi` are effectively external API clients. When possible they should use existing `MONO_API` functions. + +As a matter of expedience, the wasm project has sometimes taken advantage of static linking by +adding declarations of internal Mono functions in `src/mono/wasm/runtime/driver.c` and directly +calling Mono internals. + +In general new code should not do this. When modifying existing code, mysterious WASM failures may +be attributed to symbol signature mismatches between WASM and the Mono runtime. diff --git a/docs/design/coreclr/botr/dac-notes.md b/docs/design/coreclr/botr/dac-notes.md index 099807e9d5583..64cc01fd935e0 100644 --- a/docs/design/coreclr/botr/dac-notes.md +++ b/docs/design/coreclr/botr/dac-notes.md @@ -15,7 +15,7 @@ The DAC infrastructure (the macros and templates that control how host or target When one has no understanding of the DAC, it's easy to find the use of the DAC infrastructure annoying. The `TADDR`s and `PTR_this` and `dac_casts`, etc. seem to clutter the code and make it harder to understand. With just a little work, though, you'll find that these are not really difficult to learn. Keeping host and target addresses explicitly different is really a form of strong typing. The more diligent we are, the easier it becomes to ensure our code is correct. -Because the DAC potentially operates on a dump, the part of the VM sources we build in clr.dll (msdaccore.dll) must be non-invasive. Specifically, we usually don't want to do anything that would cause writing to the target's address space, nor can we execute any code that might cause an immediate garbage collection. (If we can defer the GC, it may be possible to allocate.) Note that the _host_ state is always mutated (temporaries, stack or local heap values); it is only mutating the _target_ space that is problematic. To enforce this, we do two things: code factoring and conditional compilation. In an ideal world, we would factor the VM code so that we would strictly isolate invasive actions in functions that are separate from non-invasive functions. +Because the DAC potentially operates on a dump, the part of the VM sources we build in mscordacwks.dll (msdaccore.dll) must be non-invasive. Specifically, we usually don't want to do anything that would cause writing to the target's address space, nor can we execute any code that might cause an immediate garbage collection. (If we can defer the GC, it may be possible to allocate.) Note that the _host_ state is always mutated (temporaries, stack or local heap values); it is only mutating the _target_ space that is problematic. To enforce this, we do two things: code factoring and conditional compilation. In an ideal world, we would factor the VM code so that we would strictly isolate invasive actions in functions that are separate from non-invasive functions. Unfortunately, we have a large code base, most of which we wrote without ever thinking about the DAC at all. We have a significant number of functions with "find or create" semantics and many other functions that have some parts that just do inspection and other parts that write to the target. Sometimes we control this with a flag passed into the function. This is common in loader code, for example. To avoid having to complete the immense job of refactoring all the VM code before we can use the DAC, we have a second method to prevent executing invasive code from out of process. We have a defined pre-processor constant, `DACCESS_COMPILE` that we use to control what parts of the code we compile into the DAC. We would like to use the `DACCESS_COMPILE` constant as little as we can, so when we DACize a new code path, we prefer to refactor whenever possible. Thus, a function that has "find or create" semantics should become two functions: one that tries to find the information and a wrapper that calls this and creates if the find fails. That way, the DAC code path can call the find function directly and avoid the creation. diff --git a/docs/design/libraries/LibraryImportGenerator/Compatibility.md b/docs/design/libraries/LibraryImportGenerator/Compatibility.md index 0e3cd08727fb9..27cf3fa45e0fd 100644 --- a/docs/design/libraries/LibraryImportGenerator/Compatibility.md +++ b/docs/design/libraries/LibraryImportGenerator/Compatibility.md @@ -2,6 +2,15 @@ Documentation on compatibility guidance and the current state. The version headings act as a rolling delta between the previous version. +## Version 2 + +The focus of version 2 is to support all repos that make up the .NET Product, including ASP.NET Core and Windows Forms, as well as all packages in dotnet/runtime. + +### User defined type marshalling + +Support for user-defined type marshalling in the source-generated marshalling is described in [UserTypeMarshallingV2.md](UserTypeMarshallingV2.md). This support replaces the designs specified in [StructMarshalling.md](StructMarshalling.md) and [SpanMarshallers.md](SpanMarshallers.md). + + ## Version 1 The focus of version 1 is to support `NetCoreApp`. This implies that anything not needed by `NetCoreApp` is subject to change. diff --git a/docs/design/libraries/LibraryImportGenerator/Pipeline.md b/docs/design/libraries/LibraryImportGenerator/Pipeline.md index 325da5e3edb8d..9533241c9ad29 100644 --- a/docs/design/libraries/LibraryImportGenerator/Pipeline.md +++ b/docs/design/libraries/LibraryImportGenerator/Pipeline.md @@ -75,11 +75,17 @@ The stub code generator itself will handle some initial setup and variable decla 1. `Pin`: data pinning in preparation for calling the generated P/Invoke - Call `Generate` on the marshalling generator for every parameter - Ignore any statements that are not `fixed` statements +1. `PinnedMarshal`: conversion of managed to native data + - Call `Generate` on the marshalling generator for every parameter 1. `Invoke`: call to the generated P/Invoke - Call `AsArgument` on the marshalling generator for every parameter - Create invocation statement that calls the generated P/Invoke -1. `KeepAlive`: keep alive any objects who's native representation won't keep them alive across the call. +1. `NotifyForSuccessfulInvoke`: Notify a marshaller that all stages through the "Invoke" stage were successful. + - Used to keep alive any objects who's native representation won't keep them alive across the call. - Call `Generate` on the marshalling generator for every parameter. +1. `UnmarshalCapture`: capture any native out parameters to avoid memory leaks if exceptions are thrown during `Unmarshal`. + - If the method has a non-void return, call `Generate` on the marshalling generator for the return + - Call `Generate` on the marshalling generator for every parameter 1. `Unmarshal`: conversion of native to managed data - If the method has a non-void return, call `Generate` on the marshalling generator for the return - Call `Generate` on the marshalling generator for every parameter @@ -97,9 +103,11 @@ try << Marshal >> << Pin >> (fixed) { + << Pinned Marshal >> << Invoke >> } - << Keep Alive >> + << Notify For Successful Invoke >> + << Unmarshal Capture >> << Unmarshal >> } finally diff --git a/docs/design/libraries/LibraryImportGenerator/SpanMarshallers.md b/docs/design/libraries/LibraryImportGenerator/SpanMarshallers.md index 320c48a5d6574..d4dcae008de96 100644 --- a/docs/design/libraries/LibraryImportGenerator/SpanMarshallers.md +++ b/docs/design/libraries/LibraryImportGenerator/SpanMarshallers.md @@ -2,6 +2,8 @@ As part of the exit criteria for the LibraryImportGenerator experiment, we have decided to introduce support for marshalling `System.Span` and `System.ReadOnlySpan` into the LibraryImportGenerator-generated stubs. This document describes design decisions made during the implementation of these marshallers. +> NOTE: These design docs are kept for historical purposes. The designs in this file are superseded by the designs in [UserTypeMarshallingV2.md](UserTypeMarshallingV2.md). + ## Design 1: "Intrinsic" support for `(ReadOnly)Span` In this design, the default support for `(ReadOnly)Span` is emitted into the marshalling stub directly and builds on the pattern we enabled for arrays. diff --git a/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md b/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md index c865ae2bae932..18fa309d3d3fe 100644 --- a/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md +++ b/docs/design/libraries/LibraryImportGenerator/StructMarshalling.md @@ -4,6 +4,8 @@ As part of the new source-generated direction for .NET Interop, we are looking a These types pose an interesting problem for a number of reasons listed below. With a few constraints, I believe we can create a system that will enable users to use their own user-defined types and pass them by-value to native code. +> NOTE: These design docs are kept for historical purposes. The designs in this file are superseded by the designs in [UserTypeMarshallingV2.md](UserTypeMarshallingV2.md). + ## Problems - What types require marshalling and what types can be passed as-is to native code? @@ -139,7 +141,7 @@ When these `CallerAllocatedBuffer` feature flag is present, the source generator Type authors can pass down the `buffer` pointer to native code by using the `TwoStageMarshalling` feature to provide a `ToNativeValue` method that returns a pointer to the first element, generally through code using `MemoryMarshal.GetReference()` and `Unsafe.AsPointer`. 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. -### Determining if a type is doesn't need marshalling +### Determining if a type doesn't need marshalling 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. diff --git a/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md b/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md new file mode 100644 index 0000000000000..072a97ab18ee5 --- /dev/null +++ b/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md @@ -0,0 +1,768 @@ +# User Defined Type Marshalling for Source-Generated Interop + +For the V1 of our source-generator, we designed support for marshalling collection types and user-defined structure types based on the designs in [StructMarshalling.md](StructMarshalling.md) and [SpanMarshallers.md](SpanMarshallers.md). As the model was adopted throughout dotnet/runtime, ASP.NET Core, WinForms, and early adopters, we recieved substantial feedback that led us to reconsider some components of the design. + +Here are some of the main feedback points on the previous design: + +- State diagram was complex + - The particular order in which methods are called on the marshallers were not simple to define. + - Handling exception scenarios without causing memory leaks was difficult. + - Supporting state preservation in "element of a collection" scenarios was going to be extremely difficult. +- Overcomplicated for simple marshallers + - The support for "Transparent Structures" in the original design added additional overhead on the base design instead of making this scenario cheaper. +- Concept Overload + - The design with optional features and multiple shapes was getting to the point that introducing people to the design was going to be difficult as there were many small options to pick. +- Limited specialization capabilities + - The V1 design mapped a single managed type to a single marshaller type. As a result, if the marshaller type required specialized support for a particular scenario such as a stack-allocated buffer optimization, then every scenario had to pay the overhead to support that conditional optimization. + - A marshaller could only be the marshaller for one managed type. As a result, if two types (such as `string` and `char`) both wanted to use the same marshalling concept, the developer would need to use two different marshaller types. + +The new design tries to address many of these concerns. + +The new marshallers have a stateless shape and a stateful shape. Stateful shapes are (currently) not allowed in "element of a collection" scenarios as handling them is difficult today, but we may improve this in the future. The stateful shapes are described in the order in which the methods will be called. Additionally, by moving away from using constructors for part of the marshalling, we can simplify the exception-handling guidance as we will only ever have one marshaller instance per parameter and it will always be assigned to the local. + +Stateless shapes avoid the problems of maintaining state and will be the primarily used shapes (they cover 90+% of our scenarios). + +The new stateless shapes provide simple mechanisms to implement marshalling for "Transparent Structures" without adding additional complexity. + +The new design has less "optional" members and each member in a shape is always used when provided. + +The new design uses a "marshaller entry-point" type to name a concept, which the user provides attributes on to point to the actual marshaller types per-scenario. This enables a marshaller entry-point type to provide specialized support for particular scenarios and support multiple managed types with one marshaller entry-point type. + +## API Diff for Supporting Attributes + +```diff +namespace System.Runtime.InteropServices.Marshalling; + +- [AttributeUsage(AttributeTargets.Struct)] +- public sealed class CustomTypeMarshallerAttribute : Attribute +- { +- public CustomTypeMarshallerAttribute(Type managedType, CustomTypeMarshallerKind marshallerKind = - CustomTypeMarshallerKind.Value) +- { +- ManagedType = managedType; +- MarshallerKind = marshallerKind; +- } +- +- public Type ManagedType { get; } +- public CustomTypeMarshallerKind MarshallerKind { get; } +- public int BufferSize { get; set; } +- public CustomTypeMarshallerDirection Direction { get; set; } = CustomTypeMarshallerDirection.Ref; +- public CustomTypeMarshallerFeatures Features { get; set; } +- public struct GenericPlaceholder +- { +- } +- } +- +- public enum CustomTypeMarshallerKind +- { +- Value, +- LinearCollection +- } +- +- [Flags] +- public enum CustomTypeMarshallerFeatures +- { +- None = 0, +- /// +- /// The marshaller owns unmanaged resources that must be freed +- /// +- UnmanagedResources = 0x1, +- /// +- /// The marshaller can use a caller-allocated buffer instead of allocating in some scenarios +- /// +- CallerAllocatedBuffer = 0x2, +- /// +- /// The marshaller uses the two-stage marshalling design for its instead of the - one-stage design. +- /// +- TwoStageMarshalling = 0x4 +- } +- [Flags] +- public enum CustomTypeMarshallerDirection +- { +- /// +- /// No marshalling direction +- /// +- [EditorBrowsable(EditorBrowsableState.Never)] +- None = 0, +- /// +- /// Marshalling from a managed environment to an unmanaged environment +- /// +- In = 0x1, +- /// +- /// Marshalling from an unmanaged environment to a managed environment +- /// +- Out = 0x2, +- /// +- /// Marshalling to and from managed and unmanaged environments +- /// +- Ref = In | Out, +- } + ++ /// ++ /// Define features for a custom type marshaller. ++ /// ++ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] ++ public sealed class CustomTypeMarshallerFeaturesAttribute : Attribute ++ { ++ /// ++ /// Desired caller buffer size for the marshaller. ++ /// ++ public int BufferSize { get; set; } ++ } ++ ++ ++ /// ++ /// Base class attribute for custom marshaller attributes. ++ /// ++ /// ++ /// Use a base class here to allow doing ManagedToUnmanagedMarshallersAttribute.GenericPlaceholder, etc. without having 3 + separate placeholder types. ++ /// For the following attribute types, any marshaller types that are provided will be validated by an analyzer to have the + correct members to prevent ++ /// developers from accidentally typoing a member like Free() and causing memory leaks. ++ /// ++ public abstract class CustomUnmanagedTypeMarshallersAttributeBase : Attribute ++ { ++ /// ++ /// Placeholder type for generic parameter ++ /// ++ public sealed class GenericPlaceholder { } ++ } ++ ++ /// ++ /// Specify marshallers used in the managed to unmanaged direction (that is, P/Invoke) ++ /// ++ [AttributeUsage(AttributeTargets.Class)] ++ public sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase ++ { ++ /// ++ /// Create instance of . ++ /// ++ /// Managed type to marshal ++ public ManagedToUnmanagedMarshallersAttribute(Type managedType) { } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the in keyword. ++ /// ++ public Type? InMarshaller { get; set; } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the ref keyword. ++ /// ++ public Type? RefMarshaller { get; set; } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the out keyword. ++ /// ++ public Type? OutMarshaller { get; set; } ++ } ++ ++ /// ++ /// Specify marshallers used in the unmanaged to managed direction (that is, Reverse P/Invoke) ++ /// ++ [AttributeUsage(AttributeTargets.Class)] ++ public sealed class UnmanagedToManagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase ++ { ++ /// ++ /// Create instance of . ++ /// ++ /// Managed type to marshal ++ public UnmanagedToManagedMarshallersAttribute(Type managedType) { } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the in keyword. ++ /// ++ public Type? InMarshaller { get; set; } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the ref keyword. ++ /// ++ public Type? RefMarshaller { get; set; } ++ ++ /// ++ /// Marshaller to use when a parameter of the managed type is passed by-value or with the out keyword. ++ /// ++ public Type? OutMarshaller { get; set; } ++ } ++ ++ /// ++ /// Specify marshaller for array-element marshalling and default struct field marshalling. ++ /// ++ [AttributeUsage(AttributeTargets.Class)] ++ public sealed class ElementMarshallerAttribute : CustomUnmanagedTypeMarshallersAttributeBase ++ { ++ /// ++ /// Create instance of . ++ /// ++ /// Managed type to marshal ++ /// Marshaller type to use for marshalling . ++ public ElementMarshallerAttribute(Type managedType, Type elementMarshaller) { } ++ } ++ ++ /// ++ /// Specifies that a particular generic parameter is the collection element's unmanaged type. ++ /// ++ /// ++ /// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume ++ /// that it is a linear collection marshaller. ++ /// ++ [AttributeUsage(AttributeTargets.GenericParameter)] ++ public sealed class ElementUnmanagedTypeAttribute : Attribute ++ { ++ } +``` + +## Design Details + +First of all, this new design continues to use the existing policy for defining "blittable" types as described in the V1 design. The rest of this document will describe the custom user-defined marshalling rules. + +In the new design, the user will first define an "entry-point type" that represents a marshalling concept. For example, if we are marshalling a `string` to a native UTF-8 encoded string, we might call the marshaller `Utf8StringMarshaller`. This new type will be a `static class`. The developer will then use the `ManagedToUnmanagedMarshallersAttribute`, `UnmanagedToManagedMarshallersAttribute`, and `ElementMarshallerAttribute` to specify which "marshaller implementation type" will be used to actually provide the marshalling. If an attribute is missing or a property on the attribute is set to `null` or left unset, this marshaller will not support marshalling in that scenario. A single type can be specified multiple times if it provides the marshalling support for multiple scenarios. + +To avoid confusion around when each marshaller applies, we define when the marshallers apply based on the C# syntax used. This helps reduce the concept load as developers don't need to remember the mapping between the previous design's `CustomTypeMarshallerDirection` enum member and the C# keyword used for a parameter, which do not match in a Reverse P/Invoke-like scenario. + +We will recommend that the marshaller types that are supplied are nested types of the "entry-point type" or the "entry-point type" itself, but we will not require it. Each specified marshaller type will have to abide by one of the following shapes depending on the scenario is supports. + +The examples below will also show which properties in each attribute support each marshaller shape. + +## Value Marshaller Shapes + +We'll start with the value marshaller shapes. These marshaller shapes support marshalling a single value. + +Each of these shapes will support marshalling the following type: + +```csharp +// Any number of generic parameters is allowed, with any constraints +struct TManaged +{ + // ... +} +``` + +The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged type the marshaller marshals the managed type to. + +### Stateless Managed->Unmanaged + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller +{ + public static class ManagedToNative + { + public static TNative ConvertToUnmanaged(TManaged managed); // Can throw exceptions + + public static ref TOther GetPinnableReference(TManaged managed); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` +### Stateless Managed->Unmanaged with Caller-Allocated Buffer + +The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller +{ + [CustomTypeMarshallerFeatures(BufferSize = 0x200)] + public static class ManagedToNative + { + public static TNative ConvertToUnmanaged(TManaged managed, Span callerAllocatedBuffer); // Can throw exceptions + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` + +### Stateless Unmanaged->Managed + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller +{ + public static class NativeToManaged + { + public static TManaged ConvertToManaged(TNative unmanaged); // Can throw exceptions + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` + +### Stateless Unmanaged->Managed with Guaranteed Unmarshalling + +This shape directs the generator to emit the `ConvertToManagedGuaranteed` call in the "GuaranteedUnmarshal" phase of marshalling. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller +{ + public static class NativeToManaged + { + public static TManaged ConvertToManagedGuaranteed(TNative unmanaged); // Should not throw exceptions + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` + +### Stateless Bidirectional +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))] +static class TMarshaller +{ + public static class Bidirectional + { + // Include members from each of the following: + // - One Stateless Managed->Unmanaged Value shape + // - One Stateless Unmanaged->Managed Value shape + } +} + +``` + +### Stateful Managed->Unmanaged + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller +{ + public struct ManagedToNative // Can be ref struct + { + public ManagedToNative(); // Optional, can throw exceptions. + + public void FromManaged(TManaged managed); // Can throw exceptions. + + public ref TIgnored GetPinnableReference(); // Result pinned for ToUnmanaged call and Invoke, but not used otherwise. + + public static ref TOther GetPinnableReference(TManaged managed); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public TNative ToUnmanaged(); // Can throw exceptions. + + public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. + + public void Free(); // Should not throw exceptions. + } +} + +``` +### Stateful Managed->Unmanaged with Caller Allocated Buffer + +The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller +{ + [CustomTypeMarshallerFeatures(BufferSize = 0x200)] + public struct ManagedToNative // Can be ref struct + { + public ManagedToNative(); // Optional, can throw exceptions. + + public void FromManaged(TManaged managed, Span buffer); // Can throw exceptions. + + public ref TIgnored GetPinnableReference(); // Result pinned for ToUnmanaged call and Invoke, but not used otherwise. + + public static ref TOther GetPinnableReference(TManaged managed); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public TNative ToUnmanaged(); // Can throw exceptions. + + public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. + + public void Free(); // Should not throw exceptions. + } +} + +``` + +### Stateful Unmanaged->Managed + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller +{ + public struct NativeToManaged // Can be ref struct + { + public NativeToManaged(); // Optional, can throw exceptions. + + public void FromUnmanaged(TNative native); // Should not throw exceptions. + + public TManaged ToManaged(); // Can throw exceptions. + + public void Free(); // Should not throw exceptions. + } +} + +``` + +### Stateful Unmanaged->Managed with Guaranteed Unmarshalling + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller +{ + public struct NativeToManaged // Can be ref struct + { + public NativeToManaged(); // Optional, can throw exceptions. + + public void FromUnmanaged(TNative native); // Should not throw exceptions. + + public TManaged ToManagedGuaranteed(); // Should not throw exceptions. + + public void Free(); // Should not throw exceptions. + } +} + +``` + +### Stateful Bidirectional +```csharp +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), RefMarshaller = typeof(Bidirectional))] +static class TMarshaller +{ + public struct Bidirectional // Can be ref struct + { + // Include members from each of the following: + // - One Stateful Managed->Unmanaged Value shape + // - One Stateful Unmanaged->Managed Value shape + } +} +``` + +## Linear (Array-like) Collection Marshaller Shapes + +We'll continue with the collection marshaller shapes. These marshaller shapes support marshalling the structure of a collection of values, where the values themselves are marshalled with marshallers of their own (using the marshaller provided in the `ElementMarshallerAttribute`). This construction allows us to compose our marshallers and to easily support arrays of custom types without needing to implement a separate marshaller for each element type. + +Each of these shapes will support marshalling the following type: + +```csharp +// Any number of generic parameters is allowed, with any constraints +struct TCollection +{ + // ... +} +``` + +A collection marshaller for a managed type will have similar generics handling as the value marshaller case; however, there is one difference. A collection marshaller must have an additional generic parameter with the `ElementUnmanagedTypeAttribute`. This parameter can optionally be constrained to `: unmanaged` (but the system will not require this). The attributed parameter will be filled in with a generics-compatible representation of the unmanaged type for the collection's element type (`nint` will be used when the native type is a pointer type). + +The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged type the marshaller marshals the managed type to. + + +### Stateless Managed->Unmanaged + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public static class ManagedToNative + { + public static TNative AllocateContainerForUnmanagedElements(TCollection managed, out int numElements); // Can throw exceptions + + public static ReadOnlySpan GetManagedValuesSource(TCollection managed); // Can throw exceptions + + public static Span GetUnmanagedValuesDestination(TNative nativeValue, int numElements); // Can throw exceptions + + public static ref TOther GetPinnableReference(TManaged managed); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` +### Stateless Managed->Unmanaged with Caller-Allocated Buffer + +The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements, including `TUnmanagedElement`. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + [CustomTypeMarshallerFeatures(BufferSize = 0x200)] + public static class ManagedToNative + { + public static TNative AllocateContainerForUnmanagedElements(TCollection managed, Span buffer, out int numElements); // Can throw exceptions + + public static ReadOnlySpan GetManagedValuesSource(TCollection managed); // Can throw exceptions + + public static Span GetUnmanagedValuesDestination(TNative nativeValue, int numElements); // Can throw exceptions + + public static ref TOther GetPinnableReference(TManaged managed); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public static void Free(TNative unmanaged); // Optional. Should not throw exceptions + } +} + +``` + +### Stateless Unmanaged->Managed + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public static class NativeToManaged + { + public static TCollection AllocateContainerForManagedElements(int length); // Can throw exceptions + + public static Span GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions + + public static ReadOnlySpan GetUnmanagedValuesSource(TNative nativeValue, int numElements); // Can throw exceptions + + public static void Free(TNative native); // Optional. Should not throw exceptions. + } +} + +``` + +### Stateless Unmanaged->Managed with Guaranteed Unmarshalling + +This shape directs the generator to emit the `ConvertToManagedGuaranteed` call in the "GuaranteedUnmarshal" phase of marshalling. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public static class NativeToManaged + { + public static TCollection AllocateContainerForManagedElementsGuaranteed(int length); // Should not throw exceptions other than OutOfMemoryException. + + public static Span GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions + + public static ReadOnlySpan GetUnmanagedValuesSource(TNative nativeValue, int numElements); // Can throw exceptions + + public static void Free(TNative native); // Optional. Should not throw exceptions. + } +} + +``` + +### Stateless Bidirectional +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public static class Bidirectional + { + // Include members from each of the following: + // - One Stateless Managed->Unmanaged Linear Collection shape + // - One Stateless Unmanaged->Managed Linear Collection shape + } +} + +``` + +### Stateful Managed->Unmanaged + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public struct ManagedToNative // Can be ref struct + { + public ManagedToNative(); // Optional, can throw exceptions. + + public void FromManaged(TCollection collection); // Can throw exceptions. + + public ReadOnlySpan GetManagedValuesSource(); // Can throw exceptions. + + public Span GetNativeValuesDestination(); // Can throw exceptions. + + public ref TIgnored GetPinnableReference(); // Optional. Can throw exceptions. + + public TNative ToUnmanaged(); // Can throw exceptions. + + public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. + } +} + +``` +### Stateful Managed->Unmanaged with Caller Allocated Buffer + +The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements. + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + [CustomTypeMarshallerFeatures(BufferSize = 0x200)] + public struct ManagedToNative // Can be ref struct + { + public ManagedToNative(); // Optional, can throw exceptions. + + public void FromManaged(TCollection collection, Span buffer); // Can throw exceptions. + + public ReadOnlySpan GetManagedValuesSource(); // Can throw exceptions. + + public Span GetNativeValuesDestination(); // Can throw exceptions. + + public ref TIgnored GetPinnableReference(); // Optional. Can throw exceptions. + + public TNative ToUnmanaged(); // Can throw exceptions. + + public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. + + public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. + } +} + +``` + +### Stateful Unmanaged->Managed + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public struct NativeToManaged // Can be ref struct + { + public NativeToManaged(); // Optional, can throw exceptions. + + public void FromUnmanaged(TNative value); // Should not throw exceptions. + + public ReadOnlySpan GetNativeValuesSource(int length); // Can throw exceptions. + + public Span GetManagedValuesDestination(int length); // Can throw exceptions. + + public TCollection ToManaged(); // Can throw exceptions + + public void Free(); // Optional. Should not throw exceptions. + } +} + +``` + +### Stateful Unmanaged->Managed with Guaranteed Unmarshalling + +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] +[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public struct NativeToManaged // Can be ref struct + { + public NativeToManaged(); // Optional, can throw exceptions. + + public void FromUnmanaged(TNative value); // Should not throw exceptions. + + public ReadOnlySpan GetNativeValuesSource(int length); // Can throw exceptions. + + public Span GetManagedValuesDestination(int length); // Can throw exceptions. + + public TCollection ToManagedGuaranteed(); // Can throw exceptions + + public void Free(); // Optional. Should not throw exceptions. + } +} + +``` + +### Stateful Bidirectional +```csharp +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] +[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] +static class TMarshaller where TUnmanagedElement : unmanaged +{ + public struct Bidirectional // Can be ref struct + { + // Include members from each of the following: + // - One Stateful Managed->Unmanaged Linear Collection shape + // - One Stateful Unmanaged->Managed Linear Collection shape + } +} +``` + +## Optional Members In Shapes + +There's a few optional members in the above shapes. This section explains what these members do and why they're optional. + +### Free method + +The `Free` method on each shape supports releasing any unmanaged (or managed in the stateful shapes) resources. This method is optional as the `Free` method is required to be called in a `finally` clause and emitting a `try-finally` block with only method calls to empty methods puts a lot of stress on the JIT to inline all of the methods and realize that they are no-ops to remove the `finally` clause. Additionally, just having the `try-finally` block wrapping the main code can cause some de-optimizations. + +### NotifyInvokeSucceeded method + +This method is called after a stub successfully invokes the target code (unmanaged code in a P/Invoke scenario, managed code in a Reverse P/Invoke scenario). As this method would be called in a very large majority of cases in P/Invoke-style scenarios and has only limited utility (its main use is to provide a good place to call `GC.KeepAlive` that does not require a `try-finally` block), we decided to make it optional. + +### Instance GetPinnableReference method on stateful shapes + +The non-static `GetPinnableReference` method on stateful shapes is provided to enable pinning a managed value as part of the marshalling process. As some types don't have values that need to be pinned to help with marshalling and pinning has some overhead, this member is optional to make the overhead pay-for-play. + +### Static GetPinnableReference method + +The static GetPinnableReference method provides a mechanism to pin a managed value and pass down the pinned value directly to native code. This allows us to provide massive performance benefits and to match built-in interop semantics. Unlike the previous design that used the `GetPinnableReference` method on the managed type in some scenarios, this design allows the "interop" pinning rules to not match the easier-to-use `GetPinnableReference` instance method, which may have differing semantics (`Span` and arrays being a prime example here). As many types aren't marshallable via only pinning, the generator does not require this method on every marshaller. + +### `-Generated` method variants + +These method variants provide a mechanism for a marshaller to state that it needs to be called during the "Generated Unmarshal" phase in the `finally` block to ensure that resources are not leaked. This feature is required only by the SafeHandle marshaller, so it is an optional extension to the model instead of being a required feature. + +## Blittability + +To determine which types are blittable and which are not, we will be following [Design 2 in StructMarshalling.md](StructMarshalling.md#determining-if-a-type-doesnt-need-marshalling). + +## Using the marshallers + +To use these marshallers the user would apply either the `NativeMarshallingAttribute` attribute to their type or a `MarshalUsingAttribute` at the marshalling location (field, parameter, or return value) with a marshalling type matching the same requirements as `NativeMarshallingAttribute`'s marshalling type. + +The marshaller type must be an entry-point marshaller type as defined above and meet the following additional requirements: + +- The type must either be: + - Non-generic + - A closed generic + - An open generic with as many generic parameters with compatible constraints as the managed type (excluding up to one generic parameter with the `ElementUnmanagedTypeAttribute`) +- If used in `NativeMarshallingAttribute`, the type should be at least as visible as the managed type. + +Passing size info for parameters will be based to the [V1 design](SpanMarshallers.md#providing-additional-data-for-collection-marshalling) and the properties/fields on `MarshalUsingAttribute` will remain unchanged. + +Here are some examples of using these new marshaller shapes with the `NativeMarshallingAttribute` and the `MarshalUsingAttribute`. + +```csharp +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +[NativeMarshalling(typeof(HResultMarshaller))] +struct HResult +{ + private int hr; +} + +[ManagedToUnmanagedMarshallers(typeof(HResult), InMarshaller = typeof(HResultMarshaller), RefMarshaller = typeof(HResultMarshaller), OutMarshaller = typeof(HResultMarshaller))] +[UnmanagedToManagedMarshallers(typeof(HResult), InMarshaller = typeof(HResultMarshaller), RefMarshaller = typeof(HResultMarshaller), OutMarshaller = typeof(HResultMarshaller))] +[ElementMarshaller(typeof(HResult), typeof(HResultMarshaller))] +public static class HResultMarshaller +{ + public static int ConvertToUnmanaged(HResult hr); + public static HResult ConvertToManaged(int hr); +} + +public static class NativeLib +{ + [LibraryImport(nameof(NativeLib))] + public static partial HResult CountArrayElements( + [MarshalUsing(typeof(ArrayMarshaller<,>))] int[] array, // Unlike the V1 system, we'll allow open generics in the V2 system in MarshalUsing since there's an extra generic parameter that the user does not provide. + out int numElements); +} + +``` diff --git a/docs/design/security/unix-tmp.md b/docs/design/security/unix-tmp.md new file mode 100644 index 0000000000000..bea8cb8f11ae6 --- /dev/null +++ b/docs/design/security/unix-tmp.md @@ -0,0 +1,45 @@ + +# Unix temporary files + +The Unix support for temporary files is different from the Windows model and developers who +are used to Windows may inadvertently create security risk if they use the same practices on Unix. + +Most notably, the Windows model for temporary files is that the operating system provides each user with a *unique*, *user-owned* temporary directory. +Moreover, all Windows users, including the service and system users, have designated user folders, including temporary folders. + +The Unix model is very different. The temp directory, assuming there is one, is often a global folder (except on MacOS). +If possible, prefer a library function like `GetTempPath()` to find the folder. Otherwise, +the `TMPDIR` environment variable is used to store the location of this folder. This variable is +widely used and supported, but it is not mandatory for all Unix implementations. It should be the preferred +mechanism for finding the Unix temporary folder if a library method is not available. It will commonly +point to either the `/tmp` or `/var/tmp` folder. These folders are not used for MacOS, so it is not recommended +to use them directly. + +Because the temporary directory is often global, any use of the temp directory should be carefully +considered. In general, the best use of the temp directory is for programs which, + +1. Will create the temporary file during their process execution +1. Do not depend on predictable temporary file/folder names +1. Will not access the file after the process exits + +In these cases, the process can create a file or files with + 1. A pseudorandom name, unlikely to cause collisions + 1. Permissions which restrict all access to owner-only, i.e. 700 for directories, 600 for files + +Any other use needs to be carefully audited, particularly if the temporary file is intended for use across +multiple processes. Some considerations: + +- **Never** write files with global access permissions +- **Always** verify that the owner of the file is the current user and that the permissions + only allow write access by the owner when reading existing files +- **Never** rely on having ownership of a particular file name. Any process can write a file with that name, + creating a denial of service. + - When creating files, consider likelihood of file name collision and performance impact of attempting + to create new names, if supported. + + If any of the above conflict with the feature requirements, consider instead writing temporary files to a + location in the user home folder. Some considerations for this model: + + - There is no automatic cleanup in user folders. Files will remain permanently or require cleanup by the app + - Some environments do not have user home folders (e.g., systemd). Consider providing an environment variable + to override the location of the temporary folder, and provide user documentation for this variable. diff --git a/docs/design/specs/Ecma-335-Augments.md b/docs/design/specs/Ecma-335-Augments.md index c0e56c9fa04cf..876d4a62f58aa 100644 --- a/docs/design/specs/Ecma-335-Augments.md +++ b/docs/design/specs/Ecma-335-Augments.md @@ -17,6 +17,7 @@ This is a list of additions and edits to be made in ECMA-335 specifications. It - [Rules for IL rewriters](#rules-for-il-rewriters) - [Checked user-defined operators](#checked-user-defined-operators) - [Atomic reads and writes](#atomic-reads-and-writes) +- [Backward branch constraints](#backward-branch-constraints) ## Signatures @@ -1020,3 +1021,7 @@ A checked user-defined operator is expected to throw an exception when the resul Section "I.12.6.6 Atomic reads and writes" adds clarification that the atomicity guarantees apply to built-in primitive value types and pointers only. A conforming CLI shall guarantee that read and write access of *built-in primitive value types and pointers* to properly aligned memory locations no larger than the native word size (the size of type native int) is atomic (see §I.12.6.2) when all the write accesses to a location are the same size. + +## Backward branch constraints + +Section "II.1.7.5 Backward branch constraints" is deleted. These constraints were not enforced by any mainstream .NET runtime and they are not respected by .NET compilers. It means that it is not possible to infer the exact state of the evaluation stack at every instruction with a single forward-pass through the CIL instruction stream. diff --git a/docs/project/dogfooding.md b/docs/project/dogfooding.md index 3ff4160095b1e..69f405a7f8076 100644 --- a/docs/project/dogfooding.md +++ b/docs/project/dogfooding.md @@ -19,9 +19,9 @@ dotnet nuget add source -n dotnet7 https://dnceng.pkgs.visualstudio.com/public/_ Then, you will be able to add the latest prerelease version of the desired package to your project. -**Example:** To add version 7.0.100-preview.5.22226.4 of the System.Data.OleDb package, use the [dotnet add package](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package) command: +**Example:** To add version 7.0-preview.5.22226.4 of the System.Data.OleDb package, use the [dotnet add package](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package) command: ``` -dotnet add package System.Data.OleDb -v 7.0.100-preview.5.22226.4 +dotnet add package System.Data.OleDb -v 7.0-preview.5.22226.4 ``` To use nightly builds of the entire runtime, follow the steps given in the rest of this document instead. @@ -30,9 +30,7 @@ To use nightly builds of the entire runtime, follow the steps given in the rest 1. Acquire the latest nightly .NET SDK by downloading and extracting a zip/tarball or using an installer from the [installers and binaries table in dotnet/installer](https://github.com/dotnet/installer#installers-and-binaries) (for example, https://aka.ms/dotnet/7.0/daily/dotnet-sdk-win-x64.zip). -2. By default, the dotnet CLI will use the globally installed SDK if it matches the major/minor version you request and has a higher revision. To force it to use a locally installed SDK, you must set an environment variable `DOTNET_MULTILEVEL_LOOKUP=0` in your shell. You can use `dotnet --info` to verify what version of the Shared Framework it is using. - -3. Reminder: if you are using a local copy of the dotnet CLI, take care that when you type `dotnet` you do not inadvertently pick up a different copy that you may have in your path. On Windows, for example, if you use a Command Prompt, a global copy may be in the path, so use the fully qualified path to your local `dotnet` (e.g. `C:\dotnet\dotnet.exe`). If you receive an error "error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0." then you may be executing an older `dotnet`. +2. If you are using a local copy of the dotnet CLI, take care that when you type `dotnet` you do not inadvertently pick up a different copy that you may have in your path. On Windows, for example, if you use a Command Prompt, a global copy may be in the path, so use the fully qualified path to your local `dotnet` (e.g. `C:\dotnet\dotnet.exe`). If you receive an error "error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0." then you may be executing an older `dotnet`. After setting up dotnet you can verify you are using the dogfooding version by executing `dotnet --info`. Here is an example output at the time of writing: ``` @@ -70,11 +68,10 @@ Learn about .NET Runtimes and SDKs: ``` -4. Our nightly builds are uploaded to dotnet-blob feeds, not NuGet - so ensure the .NET Core blob feed is in your nuget configuration in case you need other packages from .NET Core that aren't included in the download. For example, on Windows you could edit `%userprofile%\appdata\roaming\nuget\nuget.config` or on Linux edit `~/.nuget/NuGet/NuGet.Config` to add these lines: +3. Our nightly builds are uploaded to nightly feed, not NuGet - so ensure the nightly feed is in your nuget configuration in case you need other packages that aren't included in the download. For example, on Windows you could edit `%userprofile%\appdata\roaming\nuget\nuget.config` or on Linux edit `~/.nuget/NuGet/NuGet.Config` to add these lines: ```xml - - + ... ``` @@ -145,7 +142,7 @@ make it self-contained by adding a RuntimeIdentifier (RID). net7.0 - + 7.0.0-preview.5.22224.3 win-x64 diff --git a/eng/CodeAnalysis.src.globalconfig b/eng/CodeAnalysis.src.globalconfig index a9a8f29956cd2..95f58b409563a 100644 --- a/eng/CodeAnalysis.src.globalconfig +++ b/eng/CodeAnalysis.src.globalconfig @@ -411,6 +411,9 @@ dotnet_diagnostic.CA1852.severity = warning # CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' dotnet_diagnostic.CA1853.severity = warning +# CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method +dotnet_diagnostic.CA1854.severity = warning + # CA2000: Dispose objects before losing scope dotnet_diagnostic.CA2000.severity = none @@ -1070,8 +1073,8 @@ dotnet_diagnostic.SA1204.severity = none # SA1205: Partial elements should declare an access modifier dotnet_diagnostic.SA1205.severity = warning -# SA1206: Keyword ordering -dotnet_diagnostic.SA1206.severity = warning +# SA1206: Keyword ordering - TODO Re-enable as warning after https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3527 +dotnet_diagnostic.SA1206.severity = suggestion # SA1208: Using directive ordering dotnet_diagnostic.SA1208.severity = none @@ -1353,7 +1356,7 @@ dotnet_diagnostic.IDE0018.severity = suggestion dotnet_diagnostic.IDE0019.severity = suggestion # IDE0020: Use pattern matching to avoid is check followed by a cast (with variable) -dotnet_diagnostic.IDE0020.severity = suggestion +dotnet_diagnostic.IDE0020.severity = warning # IDE0021: Use expression body for constructors dotnet_diagnostic.IDE0021.severity = silent @@ -1380,13 +1383,13 @@ dotnet_diagnostic.IDE0027.severity = silent dotnet_diagnostic.IDE0028.severity = suggestion # IDE0029: Use coalesce expression -dotnet_diagnostic.IDE0029.severity = suggestion +dotnet_diagnostic.IDE0029.severity = warning # IDE0030: Use coalesce expression -dotnet_diagnostic.IDE0030.severity = suggestion +dotnet_diagnostic.IDE0030.severity = warning # IDE0031: Use null propagation -dotnet_diagnostic.IDE0031.severity = silent +dotnet_diagnostic.IDE0031.severity = warning # IDE0032: Use auto property dotnet_diagnostic.IDE0032.severity = silent @@ -1401,7 +1404,7 @@ dotnet_diagnostic.IDE0034.severity = suggestion dotnet_diagnostic.IDE0035.severity = suggestion # IDE0036: Order modifiers -dotnet_diagnostic.IDE0036.severity = suggestion +dotnet_diagnostic.IDE0036.severity = warning # IDE0037: Use inferred member name dotnet_diagnostic.IDE0037.severity = silent @@ -1455,7 +1458,7 @@ dotnet_diagnostic.IDE0052.severity = suggestion dotnet_diagnostic.IDE0053.severity = silent # IDE0054: Use compound assignment -dotnet_diagnostic.IDE0054.severity = suggestion +dotnet_diagnostic.IDE0054.severity = warning # IDE0055: Fix formatting dotnet_diagnostic.IDE0055.severity = suggestion @@ -1489,7 +1492,7 @@ dotnet_diagnostic.IDE0063.severity = silent dotnet_diagnostic.IDE0064.severity = silent # IDE0065: Misplaced using directive -dotnet_diagnostic.IDE0065.severity = suggestion +dotnet_diagnostic.IDE0065.severity = warning # IDE0066: Convert switch statement to expression dotnet_diagnostic.IDE0066.severity = suggestion @@ -1498,7 +1501,7 @@ dotnet_diagnostic.IDE0066.severity = suggestion dotnet_diagnostic.IDE0070.severity = suggestion # IDE0071: Simplify interpolation -dotnet_diagnostic.IDE0071.severity = suggestion +dotnet_diagnostic.IDE0071.severity = warning # IDE0072: Add missing cases dotnet_diagnostic.IDE0072.severity = silent @@ -1543,10 +1546,10 @@ dotnet_diagnostic.IDE0084.severity = none dotnet_diagnostic.IDE0090.severity = silent # IDE0100: Remove redundant equality -dotnet_diagnostic.IDE0100.severity = suggestion +dotnet_diagnostic.IDE0100.severity = warning # IDE0110: Remove unnecessary discard -dotnet_diagnostic.IDE0110.severity = suggestion +dotnet_diagnostic.IDE0110.severity = warning # IDE0120: Simplify LINQ expression dotnet_diagnostic.IDE0120.severity = none @@ -1567,7 +1570,7 @@ dotnet_diagnostic.IDE0160.severity = silent dotnet_diagnostic.IDE0161.severity = silent # IDE1005: Delegate invocation can be simplified. -dotnet_diagnostic.IDE1005.severity = suggestion +dotnet_diagnostic.IDE1005.severity = warning # IDE1006: Naming styles dotnet_diagnostic.IDE1006.severity = silent diff --git a/eng/CodeAnalysis.test.globalconfig b/eng/CodeAnalysis.test.globalconfig index 97bf6113e88e7..59fc4e0022deb 100644 --- a/eng/CodeAnalysis.test.globalconfig +++ b/eng/CodeAnalysis.test.globalconfig @@ -408,6 +408,9 @@ dotnet_diagnostic.CA1852.severity = none # CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)' dotnet_diagnostic.CA1853.severity = none +# CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method +dotnet_diagnostic.CA1854.severity = none + # CA2000: Dispose objects before losing scope dotnet_diagnostic.CA2000.severity = none diff --git a/eng/Subsets.props b/eng/Subsets.props index 4fbd6b5e3fbf6..1d08c11b1013a 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 @@ -312,6 +312,8 @@ Test="true" Category="clr" Condition="'$(DotNetBuildFromSource)' != 'true'"/> + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index df1d92585c1e8..d7a0af994c93e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/icu - 7c13e1a1740e54ba0c9b38636ae36195c9e9d3bd + 8ea608427e5988d3dd25130400947aad0a917bba https://github.com/dotnet/msquic b4d67ca60d3f819e2450095ab8a33a9f65513e4a - + https://github.com/dotnet/emsdk - ea10b4e5534de1806cc2e84ddd3b00eabcab962f + 3fbbd97b47b5a71d7cf3ca2e197b0b93feaf975d https://github.com/dotnet/wcf @@ -54,129 +54,129 @@ - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab https://github.com/microsoft/vstest 140434f7109d357d0158ade9e5164a4861513965 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 https://github.com/dotnet/llvm-project @@ -210,53 +210,53 @@ https://github.com/dotnet/llvm-project 54cc196d506692c366d9e116cdb3a9a56342f720 - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/runtime - f21ace52e357bbf0019da5c9e42d66705a087235 + 2b0d0d164aac758b1181329f97c87819e203617c - + https://github.com/dotnet/linker - 1481a51970586b26208a7bc6173dc77d658f3508 + 17033869c8e75e3805ba42af4c5509af72c8bb72 - + https://github.com/dotnet/xharness - a1d9a67e971fc0b8724507847491fe93f65728db + 15aa00a936f7ac3f25358a82e795df12bc7710da - + https://github.com/dotnet/xharness - a1d9a67e971fc0b8724507847491fe93f65728db + 15aa00a936f7ac3f25358a82e795df12bc7710da - + https://github.com/dotnet/xharness - a1d9a67e971fc0b8724507847491fe93f65728db + 15aa00a936f7ac3f25358a82e795df12bc7710da - + https://github.com/dotnet/arcade - ba1c3aff4be864c493031d989259ef92aaa23fc3 + ccfe6da198c5f05534863bbb1bff66e830e0c6ab https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -278,13 +278,13 @@ https://github.com/dotnet/hotreload-utils 3c641f5b79f90b0341bc0b6f728bae56ede711fd - + https://github.com/dotnet/runtime-assets - 0920468fa7db4ee8ea8bbcba186421cb92713adf + 371af1f99788b76eae14b96aad4ab7ac9b373938 - + https://github.com/dotnet/roslyn-analyzers - 114d5f2927b8afc90f169df80fdcbe8c7a644bac + 0e7f40d1709f0d7ffd316d89e452151a7365354b https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index 981629491f417..865ba86f68d0f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,40 +44,40 @@ 4.3.0-1.22206.2 4.3.0-1.22206.2 4.3.0-1.22206.2 - 7.0.0-preview1.22302.1 + 7.0.0-preview1.22310.1 4.3.0-1.22206.2 - 4.3.0-3.22281.14 + 4.4.0-1.22315.13 2.0.0-preview.4.22252.4 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 2.5.1-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 - 7.0.0-beta.22255.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 2.5.1-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 + 7.0.0-beta.22316.2 6.0.0-preview.1.102 - 7.0.0-preview.6.22305.4 - 7.0.0-preview.6.22305.4 - 7.0.0-preview.6.22305.4 + 7.0.0-preview.6.22319.5 + 7.0.0-preview.6.22319.5 + 7.0.0-preview.6.22319.5 3.1.0 - 7.0.0-preview.6.22305.4 + 7.0.0-preview.6.22319.5 1.0.0-alpha.1.22252.1 1.0.0-alpha.1.22252.1 1.0.0-alpha.1.22252.1 @@ -111,25 +111,25 @@ 5.0.0 5.0.0 4.9.0 - 7.0.0-preview.6.22305.4 + 7.0.0-preview.6.22319.5 6.0.0 4.5.4 4.5.0 - 7.0.0-preview.6.22305.4 + 7.0.0-preview.6.22319.5 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 - 7.0.0-beta.22281.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 + 7.0.0-beta.22313.1 1.0.0-prerelease.22279.1 1.0.0-prerelease.22279.1 @@ -150,9 +150,9 @@ 1.1.0 16.9.0-preview-20201201-01 - 1.0.0-prerelease.22305.1 - 1.0.0-prerelease.22305.1 - 1.0.0-prerelease.22305.1 + 1.0.0-prerelease.22320.3 + 1.0.0-prerelease.22320.3 + 1.0.0-prerelease.22320.3 1.1.0-alpha.0.22306.2 2.4.2-pre.22 0.12.0-pre.20 @@ -168,10 +168,10 @@ 7.0.0-preview-20220608.1 - 7.0.100-1.22306.1 + 7.0.100-1.22320.3 $(MicrosoftNETILLinkTasksVersion) - 7.0.0-preview.6.22306.1 + 7.0.0-preview.6.22320.2 7.0.0-alpha.1.22301.1 @@ -184,7 +184,7 @@ 11.1.0-alpha.1.22259.2 11.1.0-alpha.1.22259.2 - 7.0.0-preview.6.22281.1 + 7.0.0-preview.6.22320.1 $(MicrosoftNETWorkloadEmscriptenManifest70100Version) 1.1.87-gba258badda diff --git a/eng/build.sh b/eng/build.sh index 9c9beb471f1fb..21784abd80be3 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, armv6, armel, arm64, loongarch64, s390x or wasm." + echo " --arch (-a) Target platform: x86, x64, arm, armv6, armel, arm64, loongarch64, s390x, ppc64le 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|armv6|armel|arm64|loongarch64|s390x|wasm) + x64|x86|arm|armv6|armel|arm64|loongarch64|s390x|ppc64le|wasm) arch=$passedArch ;; *) echo "Unsupported target architecture '$2'." - echo "The allowed values are x86, x64, arm, armv6, armel, arm64, loongarch64, s390x, and wasm." + echo "The allowed values are x86, x64, arm, armv6, armel, arm64, loongarch64, s390x, ppc64le and wasm." exit 1 ;; esac diff --git a/eng/common/init-tools-native.ps1 b/eng/common/init-tools-native.ps1 index 413adea4365b1..24a5e65de1b3e 100644 --- a/eng/common/init-tools-native.ps1 +++ b/eng/common/init-tools-native.ps1 @@ -93,7 +93,7 @@ try { $ToolVersion = "" } $ArcadeToolsDirectory = "C:\arcade-tools" - if (Test-Path $ArcadeToolsDirectory -eq $False) { + if (-not (Test-Path $ArcadeToolsDirectory)) { Write-Error "Arcade tools directory '$ArcadeToolsDirectory' was not found; artifacts were not properly installed." exit 1 } @@ -103,13 +103,14 @@ try { exit 1 } $BinPathFile = "$($ToolDirectory.FullName)\binpath.txt" - if (Test-Path -Path "$BinPathFile" -eq $False) { + if (-not (Test-Path -Path "$BinPathFile")) { Write-Error "Unable to find binpath.txt in '$($ToolDirectory.FullName)' ($ToolName $ToolVersion); artifact is either installed incorrectly or is not a bootstrappable tool." exit 1 } $BinPath = Get-Content "$BinPathFile" - Write-Host "Adding $ToolName to the path ($(Convert-Path -Path $BinPath))..." - Write-Host "##vso[task.prependpath]$(Convert-Path -Path $BinPath)" + $ToolPath = Convert-Path -Path $BinPath + Write-Host "Adding $ToolName to the path ($ToolPath)..." + Write-Host "##vso[task.prependpath]$ToolPath" } } exit 0 @@ -188,7 +189,7 @@ try { Write-Host "##vso[task.prependpath]$(Convert-Path -Path $InstallBin)" return $InstallBin } - else { + elseif (-not ($PathPromotion)) { Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools install directory does not exist, installation failed' exit 1 } diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh index 4b99a9cad3b77..6d7ba15e5f2b5 100644 --- a/eng/common/native/init-compiler.sh +++ b/eng/common/native/init-compiler.sh @@ -71,7 +71,7 @@ if [[ -z "$CLR_CC" ]]; then # Set default versions if [[ -z "$majorVersion" ]]; then # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero. - if [[ "$compiler" == "clang" ]]; then versions=( 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 ) + if [[ "$compiler" == "clang" ]]; then versions=( 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 ) elif [[ "$compiler" == "gcc" ]]; then versions=( 12 11 10 9 8 7 6 5 4.9 ); fi for version in "${versions[@]}"; do diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 797f05292a851..423bd962e9661 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -635,6 +635,10 @@ function InitializeNativeTools() { InstallDirectory = "$ToolsDir" } } + if (Test-Path variable:NativeToolsOnMachine) { + Write-Host "Variable NativeToolsOnMachine detected, enabling native tool path promotion..." + $nativeArgs += @{ PathPromotion = $true } + } & "$PSScriptRoot/init-tools-native.ps1" @nativeArgs } } diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index dca61277f7fff..1b28031ab4de4 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, -armv6, -armel, -arm64, -loongarch64, -s390x, x64, x86, -wasm" + echo "BuildArch can be: -arm, -armv6, -armel, -arm64, -loongarch64, -s390x, -ppc64le, 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)" @@ -392,6 +392,10 @@ while :; do __TargetArch=wasm ;; + ppc64le|-ppc64le) + __TargetArch=ppc64le + ;; + os|-os) if [[ -n "$2" ]]; then __TargetOS="$2" diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index 931cecdeddb5b..047999bded88f 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -236,6 +236,9 @@ elseif (CLR_CMAKE_HOST_ARCH_WASM) elseif (CLR_CMAKE_HOST_ARCH_MIPS64) set(ARCH_HOST_NAME mips64) add_definitions(-DHOST_MIPS64 -DHOST_64BIT=1) +elseif (CLR_CMAKE_HOST_ARCH_POWERPC64) + set(ARCH_HOST_NAME ppc64le) + add_definitions(-DHOST_POWERPC64 -DHOST_64BIT) else () clr_unknown_arch() endif () @@ -256,6 +259,8 @@ if (CLR_CMAKE_HOST_UNIX) message("Detected Linux i686") elseif(CLR_CMAKE_HOST_UNIX_S390X) message("Detected Linux s390x") + elseif(CLR_CMAKE_HOST_UNIX_POWERPC64) + message("Detected Linux ppc64le") else() clr_unknown_arch() endif() @@ -332,6 +337,11 @@ elseif (CLR_CMAKE_TARGET_ARCH_S390X) set(ARCH_SOURCES_DIR s390x) add_compile_definitions($<$>>:TARGET_S390X>) add_compile_definitions($<$>>:TARGET_64BIT>) +elseif (CLR_CMAKE_TARGET_ARCH_POWERPC64) + set(ARCH_TARGET_NAME ppc64le) + set(ARCH_SOURCES_DIR ppc64le) + add_compile_definitions($<$>>:TARGET_POWERPC64>) + add_compile_definitions($<$>>:TARGET_64BIT>) elseif (CLR_CMAKE_TARGET_ARCH_WASM) set(ARCH_TARGET_NAME wasm) set(ARCH_SOURCES_DIR wasm) diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 573d57f9ed0dd..d21206f1f8bca 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -51,6 +51,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL Linux) set(CLR_CMAKE_HOST_UNIX_X86 1) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL s390x) set(CLR_CMAKE_HOST_UNIX_S390X 1) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le) + set(CLR_CMAKE_HOST_UNIX_POWERPC64 1) elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL mips64) set(CLR_CMAKE_HOST_UNIX_MIPS64 1) else() @@ -250,6 +252,9 @@ elseif(CLR_CMAKE_HOST_UNIX_X86) elseif(CLR_CMAKE_HOST_UNIX_S390X) set(CLR_CMAKE_HOST_ARCH_S390X 1) set(CLR_CMAKE_HOST_ARCH "s390x") +elseif(CLR_CMAKE_HOST_UNIX_POWERPC64) + set(CLR_CMAKE_HOST_ARCH_POWERPC64 1) + set(CLR_CMAKE_HOST_ARCH "ppc64le") elseif(CLR_CMAKE_HOST_BROWSER) set(CLR_CMAKE_HOST_ARCH_WASM 1) set(CLR_CMAKE_HOST_ARCH "wasm") @@ -303,6 +308,8 @@ if (CLR_CMAKE_TARGET_ARCH STREQUAL x64) set(ARM_SOFTFP 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL s390x) set(CLR_CMAKE_TARGET_ARCH_S390X 1) + elseif(CLR_CMAKE_TARGET_ARCH STREQUAL ppc64le) + set(CLR_CMAKE_TARGET_ARCH_POWERPC64 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL wasm) set(CLR_CMAKE_TARGET_ARCH_WASM 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL mips64) @@ -413,6 +420,8 @@ if(CLR_CMAKE_TARGET_UNIX) set(CLR_CMAKE_TARGET_UNIX_X86 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL s390x) set(CLR_CMAKE_TARGET_UNIX_S390X 1) + elseif(CLR_CMAKE_TARGET_ARCH STREQUAL ppc64le) + set(CLR_CMAKE_TARGET_UNIX_POWERPC64 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL wasm) set(CLR_CMAKE_TARGET_UNIX_WASM 1) elseif(CLR_CMAKE_TARGET_ARCH STREQUAL mips64) diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index 3437ce7cdae64..6697524c6596a 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -53,7 +53,7 @@ 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 MATCHES "^(armv8l|armv7l|armv6l|aarch64|arm|s390x)$") + CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv8l|armv7l|armv6l|aarch64|arm|s390x|ppc64le)$") set(TOOLSET_PREFIX "${TOOLCHAIN}-") else() set(TOOLSET_PREFIX "") diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index eaef0d65df066..6a8c8f24e9a79 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -175,6 +175,10 @@ function(find_unwind_libs UnwindLibs) find_library(UNWIND_ARCH NAMES unwind-s390x) endif() + if(CLR_CMAKE_HOST_ARCH_POWERPC64) + find_library(UNWIND_ARCH NAMES unwind-ppc64le) + endif() + if(NOT UNWIND_ARCH STREQUAL UNWIND_ARCH-NOTFOUND) set(UNWIND_LIBS ${UNWIND_ARCH}) endif() diff --git a/eng/native/init-os-and-arch.sh b/eng/native/init-os-and-arch.sh index 7a5815081ad2a..ded32e3f755f3 100644 --- a/eng/native/init-os-and-arch.sh +++ b/eng/native/init-os-and-arch.sh @@ -66,6 +66,9 @@ case "$CPUName" in arch=s390x ;; + ppc64le) + arch=ppc64le + ;; *) echo "Unknown CPU $CPUName detected, configuring as if for x64" arch=x64 diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index fca410fcb4b42..c491422ae7bce 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|armv6|arm64|loongarch64|s390x|x86)$" OR FREEBSD OR ILLUMOS) +elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|armv6|arm64|loongarch64|s390x|ppc64le|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|armv6|arm64|loongarch64|s390x|x86)$ set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() else() - message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, loongarch64, s390x and x86 are supported!") + message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, armv6, arm64, loongarch64, s390x, ppc64le and x86 are supported!") endif() -if(TARGET_ARCH_NAME STREQUAL "x86" OR TARGET_ARCH_NAME STREQUAL "s390x" OR TARGET_ARCH_NAME STREQUAL "armv6" 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" OR TARGET_ARCH_NAME STREQUAL "ppc64le") set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 9e75af0ac8f6b..d977f6c692efa 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -227,13 +227,13 @@ jobs: timeoutInMinutes: 300 ${{ else }}: timeoutInMinutes: 200 - ${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'pgo', 'jit-cfg') }}: + ${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'jit-cfg') }}: timeoutInMinutes: 270 ${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}: timeoutInMinutes: 480 ${{ if in(parameters.testGroup, 'jitstress', 'jitstress-isas-arm', 'jitstressregs-x86', 'jitstressregs', 'jitstress2-jitstressregs', 'gcstress0x3-gcstress0xc', 'ilasm') }}: timeoutInMinutes: 390 - ${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter') }}: + ${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter', 'pgo') }}: timeoutInMinutes: 510 ${{ if eq(parameters.testGroup, 'jitstress-isas-x86') }}: timeoutInMinutes: 960 @@ -397,7 +397,7 @@ jobs: ${{ if eq(parameters.runtimeFlavor, 'mono') }}: # tiered compilation isn't done on mono yet scenarios: - - normal + - normal ${{ elseif eq(variables['Build.Reason'], 'PullRequest') }}: scenarios: - no_tiered_compilation @@ -545,7 +545,9 @@ jobs: - defaultpgo - dynamicpgo - fullpgo + - fullpgo_methodprofiling - fullpgo_random_gdv + - fullpgo_random_gdv_methodprofiling_only - fullpgo_random_edge - fullpgo_random_gdv_edge ${{ if in(parameters.testGroup, 'gc-longrunning') }}: @@ -568,7 +570,6 @@ jobs: - jitelthookenabled_tiered ${{ if in(parameters.testGroup, 'jit-experimental') }}: scenarios: - - jitosr - jitosr_stress - jitosr_pgo - jitosr_stress_random diff --git a/eng/pipelines/common/templates/wasm-library-aot-tests.yml b/eng/pipelines/common/templates/wasm-library-aot-tests.yml index 982002ce90520..170be62247ca4 100644 --- a/eng/pipelines/common/templates/wasm-library-aot-tests.yml +++ b/eng/pipelines/common/templates/wasm-library-aot-tests.yml @@ -8,6 +8,7 @@ parameters: platforms: [] runAOT: false runSmokeOnlyArg: '' + shouldContinueOnError: false jobs: @@ -23,3 +24,4 @@ jobs: extraHelixArgs: /p:NeedsToBuildWasmAppsOnHelix=true ${{ parameters.extraHelixArgs }} alwaysRun: ${{ parameters.alwaysRun }} runSmokeOnlyArg: $(_runSmokeTestsOnlyArg) + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} diff --git a/eng/pipelines/common/templates/wasm-library-tests.yml b/eng/pipelines/common/templates/wasm-library-tests.yml index 8ebf5646fc7e5..365ea7386d400 100644 --- a/eng/pipelines/common/templates/wasm-library-tests.yml +++ b/eng/pipelines/common/templates/wasm-library-tests.yml @@ -7,6 +7,7 @@ parameters: platforms: [] runSmokeOnlyArg: '' scenarios: ['normal'] + shouldContinueOnError: false jobs: @@ -20,6 +21,7 @@ jobs: buildConfig: Release runtimeFlavor: mono platforms: ${{ parameters.platforms }} + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} variables: # map dependencies variables to local variables - name: librariesContainsChange diff --git a/eng/pipelines/coreclr/libraries-pgo.yml b/eng/pipelines/coreclr/libraries-pgo.yml index 0914451b55ec6..0a3346141744f 100644 --- a/eng/pipelines/coreclr/libraries-pgo.yml +++ b/eng/pipelines/coreclr/libraries-pgo.yml @@ -47,7 +47,7 @@ jobs: helixQueueGroup: libraries helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml jobParameters: - timeoutInMinutes: 150 + timeoutInMinutes: 600 testScope: innerloop liveRuntimeBuildConfig: checked dependsOnTestBuildConfiguration: Release diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index 74e6b3cfaf0f0..fd077f2e85558 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -224,6 +224,8 @@ jobs: # Run CoreCLR Tools unit tests - ${{ if eq(parameters.testGroup, 'clrTools') }}: + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset libs $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(officialBuildIdArg) -ci + displayName: Build libs - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.toolstests $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(officialBuildIdArg) -ci -test displayName: Run CoreCLR Tools unit tests diff --git a/eng/pipelines/libraries/run-test-job.yml b/eng/pipelines/libraries/run-test-job.yml index 17e3a63875d17..c6fbe831a4d9b 100644 --- a/eng/pipelines/libraries/run-test-job.yml +++ b/eng/pipelines/libraries/run-test-job.yml @@ -173,10 +173,11 @@ jobs: - defaultpgo - dynamicpgo - fullpgo + - fullpgo_methodprofiling - fullpgo_random_gdv + - fullpgo_random_gdv_methodprofiling_only - fullpgo_random_edge - fullpgo_random_gdv_edge - - jitosr - jitosr_stress - jitosr_stress_random - jitosr_pgo diff --git a/eng/pipelines/runtime-extra-platforms-other.yml b/eng/pipelines/runtime-extra-platforms-other.yml index dd8a6e0da07b1..53acaa8c3ee18 100644 --- a/eng/pipelines/runtime-extra-platforms-other.yml +++ b/eng/pipelines/runtime-extra-platforms-other.yml @@ -72,6 +72,35 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(variables['isRollingBuild'], true)) +# +# CoreCLR NativeAOT release build and additional libraries tests that are known to be passing +# Only when CoreCLR or library is changed +# +- 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 + platforms: + - windows_x64 + - windows_arm64 + jobParameters: + testGroup: innerloop + isSingleFile: true + nameSuffix: NativeAOT_Libs_Passing + buildArgs: -s clr.alljits+clr.tools+clr.nativeaotlibs+clr.nativeaotruntime+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true + timeoutInMinutes: 180 + # extra steps, run tests + extraStepsTemplate: /eng/pipelines/libraries/helix.yml + extraStepsParameters: + creator: dotnet-bot + testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig) + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + # Run net48 tests on win-x64 - template: /eng/pipelines/common/platform-matrix.yml parameters: @@ -197,7 +226,7 @@ jobs: 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 + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true timeoutInMinutes: 180 condition: >- or( @@ -361,7 +390,7 @@ jobs: jobParameters: testGroup: innerloop nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) + buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAdditionalTimezoneChecks=true timeoutInMinutes: 180 condition: >- or( diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml index 35cc083b840b7..bc75954dfe096 100644 --- a/eng/pipelines/runtime-staging.yml +++ b/eng/pipelines/runtime-staging.yml @@ -97,6 +97,8 @@ jobs: platforms: - Browser_wasm_firefox browser: firefox + # ff tests are unstable currently + shouldContinueOnError: true alwaysRun: ${{ variables.isRollingBuild }} # diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 6e588b348712f..301809c16cb37 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -260,8 +260,8 @@ jobs: testGroup: innerloop isSingleFile: true nameSuffix: NativeAOT - buildArgs: -s clr.alljits+clr.tools+clr.nativeaotlibs+clr.nativeaotruntime+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true - timeoutInMinutes: 120 + buildArgs: -s clr.alljits+clr.tools+clr.nativeaotlibs+clr.nativeaotruntime+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true /p:ArchiveTests=true + timeoutInMinutes: 180 # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml extraStepsParameters: @@ -433,7 +433,7 @@ jobs: jobParameters: testGroup: innerloop nameSuffix: AllSubsets_Mono - buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:RunSmokeTestsOnly=true /p:BuildTestsOnHelix=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true + buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:RunSmokeTestsOnly=true /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true timeoutInMinutes: 180 condition: >- or( diff --git a/eng/testing/tests.props b/eng/testing/tests.props index e91ec1bbcf0e3..7ed95b94326e3 100644 --- a/eng/testing/tests.props +++ b/eng/testing/tests.props @@ -10,18 +10,6 @@ true - - - <_withCategories Condition="'$(WithCategories)' != ''">;$(WithCategories.Trim(';')) - <_withoutCategories Condition="'$(WithoutCategories)' != ''">;$(WithoutCategories.Trim(';')) - - all - <_withCategories Condition="'$(TestScope)' == 'outerloop'">$(_withCategories);OuterLoop - <_withoutCategories Condition="'$(ArchiveTests)' == 'true'">$(_withoutCategories);IgnoreForCI - <_withoutCategories Condition="'$(TestScope)' == '' or '$(TestScope)' == 'innerloop'">$(_withoutCategories);OuterLoop - <_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing - - $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleTestRunner', '$(Configuration)', '$(NetCoreAppCurrent)')) diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets index df308f3182d44..c358ff594f3db 100644 --- a/eng/testing/tests.targets +++ b/eng/testing/tests.targets @@ -36,6 +36,18 @@ $(RunScriptHostDir)dotnet + + + <_withCategories Condition="'$(WithCategories)' != ''">;$(WithCategories.Trim(';')) + <_withoutCategories Condition="'$(WithoutCategories)' != ''">;$(WithoutCategories.Trim(';')) + + all + <_withCategories Condition="'$(TestScope)' == 'outerloop'">$(_withCategories);OuterLoop + <_withoutCategories Condition="'$(ArchiveTests)' == 'true'">$(_withoutCategories);IgnoreForCI + <_withoutCategories Condition="'$(TestScope)' == '' or '$(TestScope)' == 'innerloop'">$(_withoutCategories);OuterLoop + <_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing + + <_MonoAotCrossCompilerPath>$([MSBuild]::NormalizePath($(MonoAotCrossDir), 'mono-aot-cross')) diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 7f5cdb654efe6..4c5310cb696f9 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -5,6 +5,10 @@ true $(BundleTestAppTargets);BundleTestWasmApp true + + true + + $(NoWarn);IL2118 $([MSBuild]::NormalizeDirectory($(MonoProjectRoot), 'wasm', 'emsdk')) @@ -299,4 +303,8 @@ + + + + diff --git a/eng/testing/xunit/xunit.console.targets b/eng/testing/xunit/xunit.console.targets index 77d7363a22f4e..75d73d1037442 100644 --- a/eng/testing/xunit/xunit.console.targets +++ b/eng/testing/xunit/xunit.console.targets @@ -36,6 +36,11 @@ $(_withoutCategories.Replace(';', '%0dcategory=')) + + + $(RunScriptCommand) -xml $(TestResultsName) + + (T[] incoming, int requiredSize) private int m_length; private byte[] m_ILStream; - private int[]? m_labelList; + private __LabelInfo[]? m_labelList; private int m_labelCount; private __FixupData[]? m_fixupData; @@ -61,10 +61,13 @@ internal static T[] EnlargeArray(T[] incoming, int requiredSize) internal int m_localCount; internal SignatureHelper m_localSignature; - private int m_maxStackSize; // Maximum stack size not counting the exceptions. + private int m_curDepth; // Current stack depth, with -1 meaning unknown. + private int m_targetDepth; // Stack depth at a target of the previous instruction (when it is branching). + private int m_maxDepth; // Running max of the stack depth. - private int m_maxMidStack; // Maximum stack size for a given basic block. - private int m_maxMidStackCur; // Running count of the maximum stack size for the current basic block. + // Adjustment to add to m_maxDepth for incorrect/invalid IL. For example, when branch instructions + // with different stack depths target the same label. + private long m_depthAdjustment; internal int CurrExcStackCount => m_currExcStackCount; @@ -131,28 +134,32 @@ internal void UpdateStackSize(OpCode opcode, int stackchange) // requirements for the function. stackchange specifies the amount // by which the stacksize needs to be updated. - // Special case for the Return. Returns pops 1 if there is a - // non-void return value. - - // Update the running stacksize. m_maxMidStack specifies the maximum - // amount of stack required for the current basic block irrespective of - // where you enter the block. - m_maxMidStackCur += stackchange; - if (m_maxMidStackCur > m_maxMidStack) - m_maxMidStack = m_maxMidStackCur; - else if (m_maxMidStackCur < 0) - m_maxMidStackCur = 0; - - // If the current instruction signifies end of a basic, which basically - // means an unconditional branch, add m_maxMidStack to m_maxStackSize. - // m_maxStackSize will eventually be the sum of the stack requirements for - // each basic block. - if (opcode.EndsUncondJmpBlk()) + if (m_curDepth < 0) + { + // Current depth is "unknown". We get here when: + // * this is unreachable code. + // * the client uses explicit numeric offsets rather than Labels. + m_curDepth = 0; + } + + m_curDepth += stackchange; + if (m_curDepth < 0) { - m_maxStackSize += m_maxMidStack; - m_maxMidStack = 0; - m_maxMidStackCur = 0; + // Stack underflow. Assume our previous depth computation was flawed. + m_depthAdjustment -= m_curDepth; + m_curDepth = 0; } + else if (m_maxDepth < m_curDepth) + m_maxDepth = m_curDepth; + Debug.Assert(m_depthAdjustment >= 0); + Debug.Assert(m_curDepth >= 0); + + // Record the stack depth at a "target" of this instruction. + m_targetDepth = m_curDepth; + + // If the current instruction can't fall through, set the depth to unknown. + if (opcode.EndsUncondJmpBlk()) + m_curDepth = -1; } private int GetMethodToken(MethodBase method, Type[]? optionalParameterTypes, bool useMethodDef) @@ -280,10 +287,11 @@ private int GetLabelPos(Label lbl) if (index < 0 || index >= m_labelCount || m_labelList is null) throw new ArgumentException(SR.Argument_BadLabel); - if (m_labelList[index] < 0) + int pos = m_labelList[index].m_pos; + if (pos < 0) throw new ArgumentException(SR.Argument_BadLabelContent); - return m_labelList[index]; + return pos; } private void AddFixup(Label lbl, int pos, int instSize) @@ -306,11 +314,30 @@ private void AddFixup(Label lbl, int pos, int instSize) m_fixupLabel = lbl, m_fixupInstSize = instSize }; + + int labelIndex = lbl.GetLabelValue(); + if (labelIndex < 0 || labelIndex >= m_labelCount || m_labelList is null) + throw new ArgumentException(SR.Argument_BadLabel); + + int depth = m_labelList[labelIndex].m_depth; + int targetDepth = m_targetDepth; + Debug.Assert(depth >= -1); + Debug.Assert(targetDepth >= -1); + if (depth < targetDepth) + { + // Either unknown depth for this label or this branch location has a larger depth than previously recorded. + // In the latter case, the IL is (likely) invalid, but we just compensate for it. + if (depth >= 0) + m_depthAdjustment += targetDepth - depth; + m_labelList[labelIndex].m_depth = targetDepth; + } } internal int GetMaxStackSize() { - return m_maxStackSize; + // Limit the computed max stack to 2^16 - 1, since the value is mod`ed by 2^16 by other code. + Debug.Assert(m_depthAdjustment >= 0); + return (int)Math.Min(ushort.MaxValue, m_maxDepth + m_depthAdjustment); } private static void SortExceptions(__ExceptionInfo[] exceptions) @@ -926,7 +953,7 @@ public virtual Label BeginExceptionBlock() m_currExcStack = EnlargeArray(m_currExcStack); } - Label endLabel = DefineLabel(); + Label endLabel = DefineLabel(0); __ExceptionInfo exceptionInfo = new __ExceptionInfo(m_length, endLabel); // add the exception to the tracking list @@ -934,6 +961,10 @@ public virtual Label BeginExceptionBlock() // Make this exception the current active exception m_currExcStack[m_currExcStackCount++] = exceptionInfo; + + // Stack depth for "try" starts at zero. + m_curDepth = 0; + return endLabel; } @@ -969,7 +1000,7 @@ public virtual void EndExceptionBlock() // Check if we've already set this label. // The only reason why we might have set this is if we have a finally block. - Label label = m_labelList![endLabel.GetLabelValue()] != -1 + Label label = m_labelList![endLabel.GetLabelValue()].m_pos != -1 ? current.m_finallyEndLabel : endLabel; @@ -990,9 +1021,12 @@ public virtual void BeginExceptFilterBlock() Emit(OpCodes.Leave, current.GetEndLabel()); current.MarkFilterAddr(m_length); + + // Stack depth for "filter" starts at one. + m_curDepth = 1; } - public virtual void BeginCatchBlock(Type exceptionType) + public virtual void BeginCatchBlock(Type? exceptionType) { // Begins a catch block. Emits a branch instruction to the end of the current exception block. @@ -1020,6 +1054,9 @@ public virtual void BeginCatchBlock(Type exceptionType) } current.MarkCatchAddr(m_length, exceptionType); + + // Stack depth for "catch" starts at one. + m_curDepth = 1; } public virtual void BeginFaultBlock() @@ -1034,6 +1071,9 @@ public virtual void BeginFaultBlock() Emit(OpCodes.Leave, current.GetEndLabel()); current.MarkFaultAddr(m_length); + + // Stack depth for "fault" starts at zero. + m_curDepth = 0; } public virtual void BeginFinallyBlock() @@ -1055,7 +1095,7 @@ public virtual void BeginFinallyBlock() MarkLabel(endLabel); - Label finallyEndLabel = DefineLabel(); + Label finallyEndLabel = DefineLabel(0); current.SetFinallyEndLabel(finallyEndLabel); // generate leave for try clause @@ -1063,25 +1103,36 @@ public virtual void BeginFinallyBlock() if (catchEndAddr == 0) catchEndAddr = m_length; current.MarkFinallyAddr(m_length, catchEndAddr); + + // Stack depth for "finally" starts at zero. + m_curDepth = 0; } #endregion #region Labels public virtual Label DefineLabel() + { + // We don't know the stack depth at the label yet, so set it to -1. + return DefineLabel(-1); + } + + private Label DefineLabel(int depth) { // Declares a new Label. This is just a token and does not yet represent any particular location // within the stream. In order to set the position of the label within the stream, you must call // Mark Label. + Debug.Assert(depth >= -1); - // Delay init the lable array in case we dont use it - m_labelList ??= new int[DefaultLabelArraySize]; + // Delay init the label array in case we dont use it + m_labelList ??= new __LabelInfo[DefaultLabelArraySize]; if (m_labelCount >= m_labelList.Length) { m_labelList = EnlargeArray(m_labelList); } - m_labelList[m_labelCount] = -1; + m_labelList[m_labelCount].m_pos = -1; + m_labelList[m_labelCount].m_depth = depth; return new Label(m_labelCount++); } @@ -1098,12 +1149,39 @@ public virtual void MarkLabel(Label loc) throw new ArgumentException(SR.Argument_InvalidLabel); } - if (m_labelList[labelIndex] != -1) + if (m_labelList[labelIndex].m_pos != -1) { throw new ArgumentException(SR.Argument_RedefinedLabel); } - m_labelList[labelIndex] = m_length; + m_labelList[labelIndex].m_pos = m_length; + + int depth = m_labelList[labelIndex].m_depth; + if (depth < 0) + { + // Unknown depth for this label, indicating that it hasn't been used yet. + // If m_curDepth is unknown, we're in the Backward branch constraint case. See ECMA-335 III.1.7.5. + // The m_depthAdjustment field will compensate for violations of this constraint, as we + // discover them. That is, here we assume a depth of zero. If a (later) branch to this label + // has a positive stack depth, we'll record that as the new depth and add the delta into + // m_depthAdjustment. + if (m_curDepth < 0) + m_curDepth = 0; + m_labelList[labelIndex].m_depth = m_curDepth; + } + else if (depth < m_curDepth) + { + // A branch location with smaller stack targets this label. In this case, the IL is + // invalid, but we just compensate for it. + m_depthAdjustment += m_curDepth - depth; + m_labelList[labelIndex].m_depth = m_curDepth; + } + else if (depth > m_curDepth) + { + // Either the current depth is unknown, or a branch location with larger stack targets + // this label, so the IL is invalid. In either case, just adjust the current depth. + m_curDepth = depth; + } } #endregion @@ -1287,6 +1365,12 @@ public virtual void EndScope() #endregion } + internal struct __LabelInfo + { + internal int m_pos; // Position in the il stream, with -1 meaning unknown. + internal int m_depth; // Stack depth, with -1 meaning unknown. + } + internal struct __FixupData { internal Label m_fixupLabel; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs index 10da169b3e33f..a5f4fdd8ba7d5 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs @@ -309,7 +309,7 @@ internal int GetMaxStack() { if (m_ilGenerator != null) { - return m_ilGenerator.GetMaxStackSize() + ExceptionHandlerCount; + return m_ilGenerator.GetMaxStackSize(); } else { @@ -323,8 +323,6 @@ internal int GetMaxStack() return m_exceptions; } - internal int ExceptionHandlerCount => m_exceptions != null ? m_exceptions.Length : 0; - internal static int CalculateNumberOfExceptions(__ExceptionInfo[]? excp) { int num = 0; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs index 6acf77be549c0..8468e8f9529e8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MethodInvoker.CoreCLR.cs @@ -15,13 +15,16 @@ public MethodInvoker(MethodBase method, Signature signature) _method = method; _signature = signature; -#if USE_NATIVE_INVOKE - // Always use the native invoke; useful for testing. - _strategyDetermined = true; -#elif USE_EMIT_INVOKE - // Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing. - _invoked = true; -#endif + if (LocalAppContextSwitches.ForceInterpretedInvoke && !LocalAppContextSwitches.ForceEmitInvoke) + { + // Always use the native invoke; useful for testing. + _strategyDetermined = true; + } + else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke) + { + // Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing. + _invoked = true; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index c6c20002f2cdc..fa602e0c1dc39 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -134,9 +134,10 @@ public override AssemblyName GetName(bool copiedName) an.RawFlags = GetFlags() | AssemblyNameFlags.PublicKey; -#pragma warning disable IL3000 // System.Reflection.AssemblyName.CodeBase' always returns an empty string for assemblies embedded in a single-file app. +#pragma warning disable IL3000, SYSLIB0044 // System.Reflection.AssemblyName.CodeBase' always returns an empty string for assemblies embedded in a single-file app. + // AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported. an.CodeBase = GetCodeBase(); -#pragma warning restore IL3000 +#pragma warning restore IL3000, SYSLIB0044 #pragma warning disable SYSLIB0037 // AssemblyName.HashAlgorithm is obsolete an.HashAlgorithm = GetHashAlgorithm(); 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 a921099356ec3..486aeb72faddb 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 @@ -477,7 +477,12 @@ private static CastResult TryGet(nuint source, nuint target) private static object? ChkCastClassSpecial(void* toTypeHnd, object obj) { MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); - Debug.Assert(mt != toTypeHnd, "The check for the trivial cases should be inlined by the JIT"); + + // Normally, this case is expected to be handled by JIT inline. + // However, with PGO data JIT might decide to check a different type instead + // so this one has to be always checked here + if (toTypeHnd == mt) + goto done; for (; ; ) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs index 31c98a5bf254a..64b547b699fb7 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs @@ -24,7 +24,7 @@ public abstract class ValueType { [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "Trimmed fields don't make a difference for equality")] - public unsafe override bool Equals([NotNullWhen(true)] object? obj) + public override unsafe bool Equals([NotNullWhen(true)] object? obj) { if (null == obj) { diff --git a/src/coreclr/binder/assemblybindercommon.cpp b/src/coreclr/binder/assemblybindercommon.cpp index b3edff82d7cbc..e23c00dfc2568 100644 --- a/src/coreclr/binder/assemblybindercommon.cpp +++ b/src/coreclr/binder/assemblybindercommon.cpp @@ -1180,6 +1180,7 @@ HRESULT AssemblyBinderCommon::BindUsingHostAssemblyResolver(/* in */ INT_PTR pMa HRESULT AssemblyBinderCommon::BindUsingPEImage(/* in */ AssemblyBinder* pBinder, /* in */ BINDER_SPACE::AssemblyName *pAssemblyName, /* in */ PEImage *pPEImage, + /* in */ bool excludeAppPaths, /* [retval] [out] */ Assembly **ppAssembly) { HRESULT hr = E_FAIL; @@ -1208,7 +1209,7 @@ HRESULT AssemblyBinderCommon::BindUsingPEImage(/* in */ AssemblyBinder* pBinder pAssemblyName, true, // skipFailureCaching true, // skipVersionCompatibilityCheck - false, // excludeAppPaths + excludeAppPaths, // excludeAppPaths &bindResult); if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) diff --git a/src/coreclr/binder/customassemblybinder.cpp b/src/coreclr/binder/customassemblybinder.cpp index 98e0fd25de81b..02a8d2e918dc7 100644 --- a/src/coreclr/binder/customassemblybinder.cpp +++ b/src/coreclr/binder/customassemblybinder.cpp @@ -102,6 +102,7 @@ Exit:; } HRESULT CustomAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage, + /* in */ bool excludeAppPaths, /* [retval][out] */ BINDER_SPACE::Assembly **ppAssembly) { HRESULT hr = S_OK; @@ -128,7 +129,7 @@ HRESULT CustomAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage, IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); } - hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, &pCoreCLRFoundAssembly); + hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, excludeAppPaths, &pCoreCLRFoundAssembly); if (hr == S_OK) { _ASSERTE(pCoreCLRFoundAssembly != NULL); diff --git a/src/coreclr/binder/defaultassemblybinder.cpp b/src/coreclr/binder/defaultassemblybinder.cpp index 28157a11244cd..2461ca4b1397d 100644 --- a/src/coreclr/binder/defaultassemblybinder.cpp +++ b/src/coreclr/binder/defaultassemblybinder.cpp @@ -111,6 +111,7 @@ Exit:; #if !defined(DACCESS_COMPILE) HRESULT DefaultAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage, + /* in */ bool excludeAppPaths, /* [retval][out] */ BINDER_SPACE::Assembly **ppAssembly) { HRESULT hr = S_OK; @@ -157,7 +158,7 @@ HRESULT DefaultAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage, } } - hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, &pCoreCLRFoundAssembly); + hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, excludeAppPaths, &pCoreCLRFoundAssembly); if (hr == S_OK) { _ASSERTE(pCoreCLRFoundAssembly != NULL); diff --git a/src/coreclr/binder/inc/assemblybindercommon.hpp b/src/coreclr/binder/inc/assemblybindercommon.hpp index b3b2158715928..3bd529bd9c0a9 100644 --- a/src/coreclr/binder/inc/assemblybindercommon.hpp +++ b/src/coreclr/binder/inc/assemblybindercommon.hpp @@ -56,6 +56,7 @@ namespace BINDER_SPACE static HRESULT BindUsingPEImage(/* in */ AssemblyBinder *pBinder, /* in */ BINDER_SPACE::AssemblyName *pAssemblyName, /* in */ PEImage *pPEImage, + /* in */ bool excludeAppPaths, /* [retval] [out] */ Assembly **ppAssembly); #endif // !defined(DACCESS_COMPILE) diff --git a/src/coreclr/binder/inc/customassemblybinder.h b/src/coreclr/binder/inc/customassemblybinder.h index 9d59832f3c979..7a89c5033b9e5 100644 --- a/src/coreclr/binder/inc/customassemblybinder.h +++ b/src/coreclr/binder/inc/customassemblybinder.h @@ -18,6 +18,7 @@ class CustomAssemblyBinder final : public AssemblyBinder public: HRESULT BindUsingPEImage(PEImage* pPEImage, + bool excludeAppPaths, BINDER_SPACE::Assembly** ppAssembly) override; HRESULT BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName, diff --git a/src/coreclr/binder/inc/defaultassemblybinder.h b/src/coreclr/binder/inc/defaultassemblybinder.h index 398174c65a078..3d35854e09f3f 100644 --- a/src/coreclr/binder/inc/defaultassemblybinder.h +++ b/src/coreclr/binder/inc/defaultassemblybinder.h @@ -16,6 +16,7 @@ class DefaultAssemblyBinder final : public AssemblyBinder public: HRESULT BindUsingPEImage(PEImage* pPEImage, + bool excludeAppPaths, BINDER_SPACE::Assembly** ppAssembly) override; HRESULT BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName, diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp index 2d517279fad6f..2f1387ddd2fcf 100644 --- a/src/coreclr/classlibnative/bcltype/system.cpp +++ b/src/coreclr/classlibnative/bcltype/system.cpp @@ -90,43 +90,6 @@ FCIMPL0(INT32, SystemNative::GetExitCode) } FCIMPLEND -FCIMPL0(Object*, SystemNative::GetCommandLineArgs) -{ - FCALL_CONTRACT; - - PTRARRAYREF strArray = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_1(strArray); - - LPWSTR commandLine; - - commandLine = WszGetCommandLine(); - if (commandLine==NULL) - COMPlusThrowOM(); - - DWORD numArgs = 0; - LPWSTR* argv = SegmentCommandLine(commandLine, &numArgs); - if (!argv) - COMPlusThrowOM(); - - _ASSERTE(numArgs > 0); - - strArray = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pStringClass); - // Copy each argument into new Strings. - for(unsigned int i=0; iGetDataPtr())) + i; - SetObjectReference((OBJECTREF*)destData, (OBJECTREF)str); - } - delete [] argv; - - HELPER_METHOD_FRAME_END(); - - return OBJECTREFToObject(strArray); -} -FCIMPLEND - // Return a method info for the method were the exception was thrown FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE) { diff --git a/src/coreclr/classlibnative/bcltype/system.h b/src/coreclr/classlibnative/bcltype/system.h index 27e772be2af07..b4a773a847c39 100644 --- a/src/coreclr/classlibnative/bcltype/system.h +++ b/src/coreclr/classlibnative/bcltype/system.h @@ -43,7 +43,6 @@ class SystemNative static FCDECL1(VOID,SetExitCode,INT32 exitcode); static FCDECL0(INT32, GetExitCode); - static FCDECL0(Object*, GetCommandLineArgs); static FCDECL1(VOID, FailFast, StringObject* refMessageUNSAFE); static FCDECL2(VOID, FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode); static FCDECL2(VOID, FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE); diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 564aa84cd687e..55c7a4d0829f9 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -2501,7 +2501,7 @@ namespace serialization { namespace bin { return ErrOverflow; } - memcpy_s(dest, destSize, s.GetUTF8NoConvert(), cnt); + memcpy_s(dest, destSize, s.GetUTF8(), cnt); return cnt; } diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 6ae350448755d..9fb920f18ed60 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -6450,7 +6450,7 @@ HRESULT DacHeapWalker::MoveToNextObject() bool DacHeapWalker::GetSize(TADDR tMT, size_t &size) { - // With heap corruption, it's entierly possible that the MethodTable + // With heap corruption, it's entirely possible that the MethodTable // we get is bad. This could cause exceptions, which we will catch // and return false. This causes the heapwalker to move to the next // segment. @@ -6478,6 +6478,12 @@ bool DacHeapWalker::GetSize(TADDR tMT, size_t &size) size = AlignLarge(size); else size = Align(size); + + // If size == 0, it means we have a heap corruption and + // we will stuck in an infinite loop, so better fail the call now. + ret &= (0 < size); + // Also guard for cases where the size reported is too large and exceeds the high allocation mark. + ret &= ((tMT + size) <= mHeaps[mCurrHeap].Segments[mCurrSeg].End); } EX_CATCH { diff --git a/src/coreclr/debug/daccess/ppc64le/primitives.cpp b/src/coreclr/debug/daccess/ppc64le/primitives.cpp new file mode 100644 index 0000000000000..6bbe30049c101 --- /dev/null +++ b/src/coreclr/debug/daccess/ppc64le/primitives.cpp @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// + +#include "stdafx.h" + +#include "../../shared/ppc64le/primitives.cpp" diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index f73b1ce8afa2c..35aac26d72b22 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -647,9 +647,10 @@ ClrDataAccess::GetRegisterName(int regNum, unsigned int count, _Inout_updates_z_ return E_UNEXPECTED; const WCHAR callerPrefix[] = W("caller."); - unsigned int prefixLen = (unsigned int)ARRAY_SIZE(callerPrefix) - 1; - unsigned int regLen = (unsigned int)wcslen(regs[regNum]); - unsigned int needed = (callerFrame?prefixLen:0) + regLen + 1; + // Include null terminator in prefixLen/regLen because wcscpy_s will fail otherwise + unsigned int prefixLen = (unsigned int)ARRAY_SIZE(callerPrefix); + unsigned int regLen = (unsigned int)wcslen(regs[regNum]) + 1; + unsigned int needed = (callerFrame ? prefixLen - 1 : 0) + regLen; if (pNeeded) *pNeeded = needed; @@ -662,6 +663,8 @@ ClrDataAccess::GetRegisterName(int regNum, unsigned int count, _Inout_updates_z_ { unsigned int toCopy = prefixLen < destSize ? prefixLen : destSize; wcscpy_s(curr, toCopy, callerPrefix); + // Point to null terminator + toCopy--; curr += toCopy; destSize -= toCopy; } @@ -670,6 +673,8 @@ ClrDataAccess::GetRegisterName(int regNum, unsigned int count, _Inout_updates_z_ { unsigned int toCopy = regLen < destSize ? regLen : destSize; wcscpy_s(curr, toCopy, regs[regNum]); + // Point to null terminator + toCopy--; curr += toCopy; destSize -= toCopy; } diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 032e96457ecc1..954836a3e0f74 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -1010,7 +1010,7 @@ MemoryRange Debugger::s_hijackFunction[kMaxHijackFunctions] = RedirectedHandledJITCaseForDbgThreadControl_StubEnd), GetMemoryRangeForFunction(RedirectedHandledJITCaseForUserSuspend_Stub, RedirectedHandledJITCaseForUserSuspend_StubEnd) -#if defined(HAVE_GCCOVER) && defined(TARGET_AMD64) +#if defined(HAVE_GCCOVER) && defined(TARGET_AMD64) && defined(USE_REDIRECT_FOR_GCSTRESS) , GetMemoryRangeForFunction(RedirectedHandledJITCaseForGCStress_Stub, RedirectedHandledJITCaseForGCStress_StubEnd) diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index 39b203fa58923..a5c5ecd0fd620 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -2938,7 +2938,7 @@ void RedirectedHandledJITCaseForDbgThreadControl_StubEnd(); void RedirectedHandledJITCaseForUserSuspend_Stub(); void RedirectedHandledJITCaseForUserSuspend_StubEnd(); -#if defined(HAVE_GCCOVER) && defined(TARGET_AMD64) +#if defined(HAVE_GCCOVER) && defined(TARGET_AMD64) && defined(USE_REDIRECT_FOR_GCSTRESS) void RedirectedHandledJITCaseForGCStress_Stub(); void RedirectedHandledJITCaseForGCStress_StubEnd(); #endif // HAVE_GCCOVER && TARGET_AMD64 diff --git a/src/coreclr/debug/ee/functioninfo.cpp b/src/coreclr/debug/ee/functioninfo.cpp index f5f21da3baee8..2b287eb07fcd1 100644 --- a/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/coreclr/debug/ee/functioninfo.cpp @@ -1518,6 +1518,9 @@ DebuggerJitInfo * DebuggerMethodInfo::FindJitInfo(MethodDesc * pMD, } CONTRACTL_END; +#ifdef TARGET_ARM + addrNativeStartAddr = addrNativeStartAddr|THUMB_CODE; +#endif DebuggerJitInfo * pCheck = m_latestJitInfo; while (pCheck != NULL) diff --git a/src/coreclr/debug/ee/ppc64le/dbghelpers.S b/src/coreclr/debug/ee/ppc64le/dbghelpers.S new file mode 100644 index 0000000000000..a1ec66394511e --- /dev/null +++ b/src/coreclr/debug/ee/ppc64le/dbghelpers.S @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "asmconstants.h" +#include "unixasmmacros.inc" + +#error Unsupported platform + diff --git a/src/coreclr/debug/ee/ppc64le/primitives.cpp b/src/coreclr/debug/ee/ppc64le/primitives.cpp new file mode 100644 index 0000000000000..9b2e216d091ca --- /dev/null +++ b/src/coreclr/debug/ee/ppc64le/primitives.cpp @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// + +#include "stdafx.h" +#include "threads.h" +#include "../../shared/ppc64le/primitives.cpp" + diff --git a/src/coreclr/debug/shared/ppc64le/primitives.cpp b/src/coreclr/debug/shared/ppc64le/primitives.cpp new file mode 100644 index 0000000000000..cb4be30c89b56 --- /dev/null +++ b/src/coreclr/debug/shared/ppc64le/primitives.cpp @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +//***************************************************************************** +// File: primitives.cpp +// + +// +// Platform-specific debugger primitives +// +//***************************************************************************** + +#include "primitives.h" + +#error Unsupported platform + diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index f6dc44d8b06ee..6a96d6c03e0ea 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -415,7 +415,6 @@ BEGIN IDS_EE_SIZECONTROLBADTYPE "Array size control parameter type not supported." IDS_EE_SAFEARRAYSZARRAYMISMATCH "SafeArray cannot be marshaled to this array type because it has either nonzero lower bounds or more than one dimension." - IDS_EE_ASSEMBLY_GETTYPE_CANNONT_HAVE_ASSEMBLY_SPEC "Type names passed to Assembly.GetType() must not specify an assembly." IDS_EE_NEEDS_ASSEMBLY_SPEC "Typename needs an assembly qualifier." IDS_EE_FILELOAD_ERROR_GENERIC "Could not load file or assembly '%1'. %2" diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index ed503b4875ad6..351ff690aaca6 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -305,7 +305,6 @@ #define IDS_CLASSLOAD_OVERLAPPING_INTERFACES 0x1a80 #define IDS_CLASSLOAD_32BITCLRLOADING64BITASSEMBLY 0x1a81 -#define IDS_EE_ASSEMBLY_GETTYPE_CANNONT_HAVE_ASSEMBLY_SPEC 0x1a84 #define IDS_EE_NEEDS_ASSEMBLY_SPEC 0x1a87 diff --git a/src/coreclr/gc/env/etmdummy.h b/src/coreclr/gc/env/etmdummy.h index 556372127577a..575e3067cf89a 100644 --- a/src/coreclr/gc/env/etmdummy.h +++ b/src/coreclr/gc/env/etmdummy.h @@ -78,6 +78,7 @@ #define FireEtwThreadPoolWorkerThreadAdjustmentAdjustment(AverageThroughput, NewWorkerThreadCount, Reason, ClrInstanceID) 0 #define FireEtwThreadPoolWorkerThreadAdjustmentStats(Duration, Throughput, ThreadWave, ThroughputWave, ThroughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, Confidence, NewControlSetting, NewThreadWaveMagnitude, ClrInstanceID) 0 #define FireEtwThreadPoolWorkerThreadWait(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID) 0 +#define FireEtwThreadPoolMinMaxThreads (MinWorkerThreads, MaxWorkerThreads, MinIOCompletionThreads, MaxIOCompletionThreads, ClrInstanceID) 0 #define FireEtwThreadPoolWorkingThreadCount(Count, ClrInstanceID) 0 #define FireEtwThreadPoolEnqueue(WorkID, ClrInstanceID) 0 #define FireEtwThreadPoolDequeue(WorkID, ClrInstanceID) 0 diff --git a/src/coreclr/gc/env/gcenv.os.h b/src/coreclr/gc/env/gcenv.os.h index c37f62509e8bc..25a15e3847d34 100644 --- a/src/coreclr/gc/env/gcenv.os.h +++ b/src/coreclr/gc/env/gcenv.os.h @@ -6,17 +6,6 @@ #ifndef __GCENV_OS_H__ #define __GCENV_OS_H__ -#ifdef Sleep -// This is a funny workaround for the fact that "common.h" defines Sleep to be -// Dont_Use_Sleep, with the hope of causing linker errors whenever someone tries to use sleep. -// -// However, GCToOSInterface defines a function called Sleep, which (due to this define) becomes -// "Dont_Use_Sleep", which the GC in turn happily uses. The symbol that GCToOSInterface actually -// exported was called "GCToOSInterface::Dont_Use_Sleep". While we progress in making the GC standalone, -// we'll need to break the dependency on common.h (the VM header) and this problem will become moot. -#undef Sleep -#endif // Sleep - #ifdef HAS_SYSTEM_YIELDPROCESSOR // YieldProcessor is defined to Dont_Use_YieldProcessor. Restore it to the system-default implementation for the GC. #undef YieldProcessor diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index ec96a2e6fb65d..1021d669b2dc3 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -44526,9 +44526,25 @@ Object * GCHeap::NextObj (Object * object) return NULL; } - if ((nextobj < heap_segment_mem(hs)) || - (nextobj >= heap_segment_allocated(hs) && hs != hp->ephemeral_heap_segment) || - (nextobj >= hp->alloc_allocated)) + if (nextobj < heap_segment_mem (hs)) + { + return NULL; + } + + uint8_t* saved_alloc_allocated = hp->alloc_allocated; + heap_segment* saved_ephemeral_heap_segment = hp->ephemeral_heap_segment; + + // We still want to verify nextobj that lands between heap_segment_allocated and alloc_allocated + // on the ephemeral segment. In regions these 2 could be changed by another thread so we need + // to make sure they are still in sync by the time we check. If they are not in sync, we just + // bail which means we don't validate the next object during that small window and that's fine. + // + // We also miss validating nextobj if it's in the segment that just turned into the new ephemeral + // segment since we saved which is also a very small window and again that's fine. + if ((nextobj >= heap_segment_allocated (hs)) && + ((hs != saved_ephemeral_heap_segment) || + !in_range_for_segment(saved_alloc_allocated, saved_ephemeral_heap_segment) || + (nextobj >= saved_alloc_allocated))) { return NULL; } diff --git a/src/coreclr/gc/unix/cgroup.cpp b/src/coreclr/gc/unix/cgroup.cpp index 34f7f4f47f62d..50069e469147e 100644 --- a/src/coreclr/gc/unix/cgroup.cpp +++ b/src/coreclr/gc/unix/cgroup.cpp @@ -47,6 +47,10 @@ Module Name: #define CGROUP1_MEMORY_LIMIT_FILENAME "/memory.limit_in_bytes" #define CGROUP2_MEMORY_LIMIT_FILENAME "/memory.max" #define CGROUP_MEMORY_STAT_FILENAME "/memory.stat" +#define CGROUP1_MEMORY_USAGE_FILENAME "/memory.usage_in_bytes" +#define CGROUP2_MEMORY_USAGE_FILENAME "/memory.current" +#define CGROUP1_MEMORY_STAT_INACTIVE_FIELD "total_inactive_file " +#define CGROUP2_MEMORY_STAT_INACTIVE_FIELD "inactive_file " extern bool ReadMemoryValueFromFile(const char* filename, uint64_t* val); @@ -56,36 +60,11 @@ class CGroup static int s_cgroup_version; static char *s_memory_cgroup_path; - - static const char *s_mem_stat_key_names[]; - static size_t s_mem_stat_key_lengths[]; - static size_t s_mem_stat_n_keys; public: static void Initialize() { s_cgroup_version = FindCGroupVersion(); s_memory_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1MemorySubsystem : nullptr); - - if (s_cgroup_version == 1) - { - s_mem_stat_n_keys = 4; - s_mem_stat_key_names[0] = "total_inactive_anon "; - s_mem_stat_key_names[1] = "total_active_anon "; - s_mem_stat_key_names[2] = "total_dirty "; - s_mem_stat_key_names[3] = "total_unevictable "; - } - else - { - s_mem_stat_n_keys = 3; - s_mem_stat_key_names[0] = "anon "; - s_mem_stat_key_names[1] = "file_dirty "; - s_mem_stat_key_names[2] = "unevictable "; - } - - for (size_t i = 0; i < s_mem_stat_n_keys; i++) - { - s_mem_stat_key_lengths[i] = strlen(s_mem_stat_key_names[i]); - } } static void Cleanup() @@ -113,9 +92,9 @@ class CGroup if (s_cgroup_version == 0) return false; else if (s_cgroup_version == 1) - return GetCGroupMemoryUsage(val); + return GetCGroupMemoryUsage(val, CGROUP1_MEMORY_USAGE_FILENAME, CGROUP1_MEMORY_STAT_INACTIVE_FIELD); else if (s_cgroup_version == 2) - return GetCGroupMemoryUsage(val); + return GetCGroupMemoryUsage(val, CGROUP2_MEMORY_USAGE_FILENAME, CGROUP2_MEMORY_STAT_INACTIVE_FIELD); else { assert(!"Unknown cgroup version."); @@ -401,8 +380,38 @@ class CGroup return result; } - static bool GetCGroupMemoryUsage(size_t *val) + static bool GetCGroupMemoryUsage(size_t *val, const char *filename, const char *inactiveFileFieldName) { + // Use the same way to calculate memory load as popular container tools (Docker, Kubernetes, Containerd etc.) + // For cgroup v1: value of 'memory.usage_in_bytes' minus 'total_inactive_file' value of 'memory.stat' + // For cgroup v2: value of 'memory.current' minus 'inactive_file' value of 'memory.stat' + + char* mem_usage_filename = nullptr; + if (asprintf(&mem_usage_filename, "%s%s", s_memory_cgroup_path, filename) < 0) + return false; + + uint64_t temp = 0; + + size_t usage = 0; + + bool result = ReadMemoryValueFromFile(mem_usage_filename, &temp); + if (result) + { + if (temp > std::numeric_limits::max()) + { + usage = std::numeric_limits::max(); + } + else + { + usage = (size_t)temp; + } + } + + free(mem_usage_filename); + + if (!result) + return result; + if (s_memory_cgroup_path == nullptr) return false; @@ -417,44 +426,38 @@ class CGroup char *line = nullptr; size_t lineLen = 0; - size_t readValues = 0; + bool foundInactiveFileValue = false; char* endptr; - *val = 0; - while (getline(&line, &lineLen, stat_file) != -1 && readValues < s_mem_stat_n_keys) + size_t inactiveFileFieldNameLength = strlen(inactiveFileFieldName); + + while (getline(&line, &lineLen, stat_file) != -1) { - for (size_t i = 0; i < s_mem_stat_n_keys; i++) + if (strncmp(line, inactiveFileFieldName, inactiveFileFieldNameLength) == 0) { - if (strncmp(line, s_mem_stat_key_names[i], s_mem_stat_key_lengths[i]) == 0) + errno = 0; + const char* startptr = line + inactiveFileFieldNameLength; + size_t inactiveFileValue = strtoll(startptr, &endptr, 10); + if (endptr != startptr && errno == 0) { - errno = 0; - const char* startptr = line + s_mem_stat_key_lengths[i]; - *val += strtoll(startptr, &endptr, 10); - if (endptr != startptr && errno == 0) - readValues++; - - break; + foundInactiveFileValue = true; + *val = usage - inactiveFileValue; } + + break; } } fclose(stat_file); free(line); - if (readValues == s_mem_stat_n_keys) - return true; - - return false; + return foundInactiveFileValue; } }; int CGroup::s_cgroup_version = 0; char *CGroup::s_memory_cgroup_path = nullptr; -const char *CGroup::s_mem_stat_key_names[4] = {}; -size_t CGroup::s_mem_stat_key_lengths[4] = {}; -size_t CGroup::s_mem_stat_n_keys = 0; - void InitializeCGroup() { CGroup::Initialize(); diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 8b536ad9dd7d8..4ad5f4b3795e8 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -876,21 +876,29 @@ bool ReadMemoryValueFromFile(const char* filename, uint64_t* val) return result; } +#define UPDATE_CACHE_SIZE_AND_LEVEL(CACHE_LEVEL) if (size > cacheSize) { cacheSize = size; cacheLevel = CACHE_LEVEL; } + static size_t GetLogicalProcessorCacheSizeFromOS() { + size_t cacheLevel = 0; size_t cacheSize = 0; + size_t size; #ifdef _SC_LEVEL1_DCACHE_SIZE - cacheSize = std::max(cacheSize, ( size_t) sysconf(_SC_LEVEL1_DCACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL1_DCACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(1) #endif #ifdef _SC_LEVEL2_CACHE_SIZE - cacheSize = std::max(cacheSize, ( size_t) sysconf(_SC_LEVEL2_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL2_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(2) #endif #ifdef _SC_LEVEL3_CACHE_SIZE - cacheSize = std::max(cacheSize, ( size_t) sysconf(_SC_LEVEL3_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL3_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(3) #endif #ifdef _SC_LEVEL4_CACHE_SIZE - cacheSize = std::max(cacheSize, ( size_t) sysconf(_SC_LEVEL4_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL4_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(4) #endif #if defined(TARGET_LINUX) && !defined(HOST_ARM) && !defined(HOST_X86) @@ -901,25 +909,39 @@ static size_t GetLogicalProcessorCacheSizeFromOS() // for the platform. Currently musl and arm64 should be only cases to use // this method to determine cache size. // - size_t size; - - if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index0/size", &size)) - cacheSize = std::max(cacheSize, size); - if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index1/size", &size)) - cacheSize = std::max(cacheSize, size); - if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index2/size", &size)) - cacheSize = std::max(cacheSize, size); - if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index3/size", &size)) - cacheSize = std::max(cacheSize, size); - if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index4/size", &size)) - cacheSize = std::max(cacheSize, size); + size_t level; + char path_to_size_file[] = "/sys/devices/system/cpu/cpu0/cache/index-/size"; + char path_to_level_file[] = "/sys/devices/system/cpu/cpu0/cache/index-/level"; + int index = 40; + assert(path_to_size_file[index] == '-'); + assert(path_to_level_file[index] == '-'); + + for (int i = 0; i < 5; i++) + { + path_to_size_file[index] = (char)(48 + i); + + if (ReadMemoryValueFromFile(path_to_size_file, &size)) + { + path_to_level_file[index] = (char)(48 + i); + + if (ReadMemoryValueFromFile(path_to_level_file, &level)) + { + UPDATE_CACHE_SIZE_AND_LEVEL(level) + } + else + { + cacheSize = std::max(cacheSize, size); + } + } + } } #endif -#if defined(HOST_ARM64) && !defined(TARGET_OSX) +#if (defined(HOST_ARM64) || defined(HOST_LOONGARCH64)) && !defined(TARGET_OSX) if (cacheSize == 0) { - // It is currently expected to be missing cache size info + // We expect to get the L3 cache size for Arm64 but currently expected to be missing that info + // from most of the machines. // // _SC_LEVEL*_*CACHE_SIZE is not yet present. Work is in progress to enable this for arm64 // @@ -964,6 +986,38 @@ static size_t GetLogicalProcessorCacheSizeFromOS() } #endif +#if (defined(HOST_ARM64) || defined(HOST_LOONGARCH64)) && !defined(TARGET_OSX) + if (cacheLevel != 3) + { + // We expect to get the L3 cache size for Arm64 but currently expected to be missing that info + // from most of the machines. + // Hence, just use the following heuristics at best depending on the CPU count + // 1 ~ 4 : 4 MB + // 5 ~ 16 : 8 MB + // 17 ~ 64 : 16 MB + // 65+ : 32 MB + DWORD logicalCPUs = g_totalCpuCount; + if (logicalCPUs < 5) + { + cacheSize = 4; + } + else if (logicalCPUs < 17) + { + cacheSize = 8; + } + else if (logicalCPUs < 65) + { + cacheSize = 16; + } + else + { + cacheSize = 32; + } + + cacheSize *= (1024 * 1024); + } +#endif + return cacheSize; } @@ -1037,15 +1091,10 @@ size_t GCToOSInterface::GetCacheSizePerLogicalCpu(bool trueSize) size_t maxSize, maxTrueSize; maxSize = maxTrueSize = GetLogicalProcessorCacheSizeFromOS(); // Returns the size of the highest level processor cache -#if defined(HOST_ARM64) - // Bigger gen0 size helps arm64 targets - maxSize = maxTrueSize * 3; -#endif - s_maxSize = maxSize; s_maxTrueSize = maxTrueSize; - // printf("GetCacheSizePerLogicalCpu returns %d, adjusted size %d\n", maxSize, maxTrueSize); + // printf("GetCacheSizePerLogicalCpu returns %zu, adjusted size %zu\n", maxSize, maxTrueSize); return trueSize ? maxTrueSize : maxSize; } diff --git a/src/coreclr/gc/windows/gcenv.windows.cpp b/src/coreclr/gc/windows/gcenv.windows.cpp index 8bb35badd6c2f..ca7cc4132e5ee 100644 --- a/src/coreclr/gc/windows/gcenv.windows.cpp +++ b/src/coreclr/gc/windows/gcenv.windows.cpp @@ -402,6 +402,8 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION *GetLPI(PDWORD nEntries) size_t GetLogicalProcessorCacheSizeFromOS() { size_t cache_size = 0; + size_t cache_level = 0; + DWORD nEntries = 0; // Try to use GetLogicalProcessorInformation API and get a valid pointer to the SLPI array if successful. Returns NULL @@ -424,7 +426,11 @@ size_t GetLogicalProcessorCacheSizeFromOS() { if (pslpi[i].Relationship == RelationCache) { - last_cache_size = max(last_cache_size, pslpi[i].Cache.Size); + if (last_cache_size < pslpi[i].Cache.Size) + { + last_cache_size = pslpi[i].Cache.Size; + cache_level = pslpi[i].Cache.Level; + } } } cache_size = last_cache_size; @@ -434,6 +440,39 @@ size_t GetLogicalProcessorCacheSizeFromOS() if(pslpi) delete[] pslpi; // release the memory allocated for the SLPI array. +#if defined(TARGET_ARM64) + if (cache_level != 3) + { + uint32_t totalCPUCount = GCToOSInterface::GetTotalProcessorCount(); + + // We expect to get the L3 cache size for Arm64 but currently expected to be missing that info + // from most of the machines. + // Hence, just use the following heuristics at best depending on the CPU count + // 1 ~ 4 : 4 MB + // 5 ~ 16 : 8 MB + // 17 ~ 64 : 16 MB + // 65+ : 32 MB + if (totalCPUCount < 5) + { + cache_size = 4; + } + else if (totalCPUCount < 17) + { + cache_size = 8; + } + else if (totalCPUCount < 65) + { + cache_size = 16; + } + else + { + cache_size = 32; + } + + cache_size *= (1024 * 1024); + } +#endif // TARGET_ARM64 + return cache_size; } @@ -836,15 +875,10 @@ size_t GCToOSInterface::GetCacheSizePerLogicalCpu(bool trueSize) maxSize = maxTrueSize = GetLogicalProcessorCacheSizeFromOS() ; // Returns the size of the highest level processor cache -#if defined(TARGET_ARM64) - // Bigger gen0 size helps arm64 targets - maxSize = maxTrueSize * 3; -#endif - s_maxSize = maxSize; s_maxTrueSize = maxTrueSize; - // printf("GetCacheSizePerLogicalCpu returns %d, adjusted size %d\n", maxSize, maxTrueSize); + // printf("GetCacheSizePerLogicalCpu returns %zu, adjusted size %zu\n", maxSize, maxTrueSize); return trueSize ? maxTrueSize : maxSize; } diff --git a/src/coreclr/ilasm/assembler.h b/src/coreclr/ilasm/assembler.h index 76f6787021fd3..43ecddf2ea0b5 100644 --- a/src/coreclr/ilasm/assembler.h +++ b/src/coreclr/ilasm/assembler.h @@ -53,10 +53,6 @@ #define dwUniBuf 16384 -#ifdef TARGET_UNIX -extern char *g_pszExeFile; -#endif - extern WCHAR wzUniBuf[]; // Unicode conversion global buffer (assem.cpp) class Class; diff --git a/src/coreclr/ilasm/main.cpp b/src/coreclr/ilasm/main.cpp index 146e8640b3cb4..d6d6e9201b1bf 100644 --- a/src/coreclr/ilasm/main.cpp +++ b/src/coreclr/ilasm/main.cpp @@ -29,9 +29,6 @@ static DWORD g_dwSubsystem=(DWORD)-1,g_dwComImageFlags=(DWORD)-1,g_dwFileAlig static ULONGLONG g_stBaseAddress=0; static size_t g_stSizeOfStackReserve=0; extern unsigned int g_uConsoleCP; -#ifdef TARGET_UNIX -char * g_pszExeFile; -#endif void MakeTestFile(_In_ __nullterminated char* szFileName) { @@ -855,7 +852,6 @@ extern "C" int _cdecl wmain(int argc, _In_ WCHAR **argv) #ifdef TARGET_UNIX int main(int argc, char* str[]) { - g_pszExeFile = str[0]; if (0 != PAL_Initialize(argc, str)) { fprintf(stderr,"Error: Fail to PAL_Initialize\n"); diff --git a/src/coreclr/ildasm/dasm.cpp b/src/coreclr/ildasm/dasm.cpp index 03999e3c61872..9942397f9da6d 100644 --- a/src/coreclr/ildasm/dasm.cpp +++ b/src/coreclr/ildasm/dasm.cpp @@ -123,7 +123,6 @@ BOOL g_fCustomInstructionEncodingSystem = FALSE; COR_FIELD_OFFSET *g_rFieldOffset = NULL; ULONG g_cFieldsMax, g_cFieldOffsets; -char* g_pszExeFile; char g_szInputFile[MAX_FILENAME_LENGTH]; // in UTF-8 WCHAR g_wszFullInputFile[MAX_PATH + 1]; // in UTF-16 char g_szOutputFile[MAX_FILENAME_LENGTH]; // in UTF-8 diff --git a/src/coreclr/ildasm/windasm.cpp b/src/coreclr/ildasm/windasm.cpp index 6ef983bc583c5..bf80bad26b6cf 100644 --- a/src/coreclr/ildasm/windasm.cpp +++ b/src/coreclr/ildasm/windasm.cpp @@ -55,7 +55,6 @@ extern char g_szAsmCodeIndent[]; extern DWORD g_Mode; -extern char* g_pszExeFile; extern char g_szInputFile[]; // in UTF-8 extern WCHAR g_wszFullInputFile[]; // in UTF-16 extern char g_szOutputFile[]; // in UTF-8 @@ -424,37 +423,10 @@ int ProcessOneArg(_In_ __nullterminated char* szArg, _Out_ char** ppszObjFileNam return 0; } -char* UTF8toANSI(_In_ __nullterminated char* szUTF) -{ - ULONG32 L = (ULONG32) strlen(szUTF)+16; - WCHAR* wzUnicode = new WCHAR[L]; - memset(wzUnicode,0,L*sizeof(WCHAR)); - WszMultiByteToWideChar(CP_UTF8,0,szUTF,-1,wzUnicode,L); - L <<= 2; - char* szANSI = new char[L]; - memset(szANSI,0,L); - WszWideCharToMultiByte(g_uConsoleCP,0,wzUnicode,-1,szANSI,L,NULL,NULL); - VDELETE(wzUnicode); - return szANSI; -} -char* ANSItoUTF8(_In_ __nullterminated char* szANSI) -{ - ULONG32 L = (ULONG32) strlen(szANSI)+16; - WCHAR* wzUnicode = new WCHAR[L]; - memset(wzUnicode,0,L*sizeof(WCHAR)); - WszMultiByteToWideChar(g_uConsoleCP,0,szANSI,-1,wzUnicode,L); - L *= 3; - char* szUTF = new char[L]; - memset(szUTF,0,L); - WszWideCharToMultiByte(CP_UTF8,0,wzUnicode,-1,szUTF,L,NULL,NULL); - VDELETE(wzUnicode); - return szUTF; -} - -int ParseCmdLineW(_In_ __nullterminated WCHAR* wzCmdLine, _Out_ char** ppszObjFileName) +#ifdef HOST_WINDOWS +int ParseCmdLineW(int argc, _In_ __nullterminated wchar_t* argv[], _Out_ char** ppszObjFileName) { - int argc,ret=0; - LPWSTR* argv= SegmentCommandLine(wzCmdLine, (DWORD*)&argc); + int ret=0; char* szArg = new char[2048]; for(int i=1; i < argc; i++) { @@ -465,54 +437,32 @@ int ParseCmdLineW(_In_ __nullterminated WCHAR* wzCmdLine, _Out_ char** ppszObjFi VDELETE(szArg); return ret; } - -int ParseCmdLineA(_In_ __nullterminated char* szCmdLine, _Out_ char** ppszObjFileName) +#else +int ParseCmdLine(int argc, _In_ __nullterminated char* argv[], _Out_ char** ppszObjFileName) { - if((szCmdLine == NULL)||(*szCmdLine == 0)) return 0; - - // ANSI to UTF-8 - char* szCmdLineUTF = ANSItoUTF8(szCmdLine); - - // Split into argv[] - int argc=0, ret = 0; - DynamicArray argv; - char* pch; - char* pchend; - bool bUnquoted = true; - - pch = szCmdLineUTF; - pchend = pch+strlen(szCmdLineUTF); - while(pch) + int ret = 0; + char* szArg = new char[2048]; + for (int i = 1; i < argc; i++) { - for(; *pch == ' '; pch++); // skip the blanks - argv[argc++] = pch; - for(; pch < pchend; pch++) - { - if(*pch == '"') bUnquoted = !bUnquoted; - else if((*pch == ' ')&&bUnquoted) break; - } - - if(pch < pchend) *pch++ = 0; - else break; + if ((ret = ProcessOneArg(argv[i], ppszObjFileName)) != 0) break; } - - for(int i=1; i < argc; i++) - { - if((ret = ProcessOneArg(argv[i],ppszObjFileName)) != 0) break; - } - VDELETE(szCmdLineUTF); + VDELETE(szArg); return ret; } +#endif -int __cdecl main(int nCmdShow, char* lpCmdLine[]) +#ifdef HOST_WINDOWS +int __cdecl wmain(int argc, wchar_t* argv[]) +#else +int main(int argc, char* argv[]) +#endif { #if defined(TARGET_UNIX) - if (0 != PAL_Initialize(nCmdShow, lpCmdLine)) + if (0 != PAL_Initialize(argc, argv)) { printError(g_pFile, "Error: Fail to PAL_Initialize\n"); exit(1); } - g_pszExeFile = lpCmdLine[0]; #endif #ifdef HOST_WINDOWS @@ -552,7 +502,12 @@ int __cdecl main(int nCmdShow, char* lpCmdLine[]) g_hResources = WszGetModuleHandle(NULL); #endif - iCommandLineParsed = ParseCmdLineW((wzCommandLine = GetCommandLineW()),&g_pszObjFileName); + +#ifdef HOST_WINDOWS + iCommandLineParsed = ParseCmdLineW(argc, argv, &g_pszObjFileName); +#else + iCommandLineParsed = ParseCmdLine(argc, argv, &g_pszObjFileName); +#endif if(!g_fLimitedVisibility) { diff --git a/src/coreclr/inc/contxt.h b/src/coreclr/inc/contxt.h deleted file mode 100644 index 1611e7616f5d3..0000000000000 --- a/src/coreclr/inc/contxt.h +++ /dev/null @@ -1,3471 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/* this ALWAYS GENERATED file contains the definitions for the interfaces */ - - -/* File created by MIDL compiler version 5.01.0164 */ -/* at Mon May 01 14:39:38 2000 - */ -/* Compiler settings for contxt.idl: - Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext - error checks: allocation ref bounds_check enum stub_data -*/ -//@@MIDL_FILE_HEADING( ) - - -/* verify that the version is high enough to compile this file*/ -#ifndef __REQUIRED_RPCNDR_H_VERSION__ -#define __REQUIRED_RPCNDR_H_VERSION__ 440 -#endif - -#include "rpc.h" -#include "rpcndr.h" - -#ifndef __RPCNDR_H_VERSION__ -#error this stub requires an updated version of -#endif // __RPCNDR_H_VERSION__ - -#ifndef COM_NO_WINDOWS_H -#include "windows.h" -#include "ole2.h" -#endif /*COM_NO_WINDOWS_H*/ - -#ifndef __contxt_h__ -#define __contxt_h__ - -#ifdef __cplusplus -extern "C"{ -#endif - -/* Forward Declarations */ - -#ifndef __IEnumContextProps_FWD_DEFINED__ -#define __IEnumContextProps_FWD_DEFINED__ -typedef interface IEnumContextProps IEnumContextProps; -#endif /* __IEnumContextProps_FWD_DEFINED__ */ - - -#ifndef __IContext_FWD_DEFINED__ -#define __IContext_FWD_DEFINED__ -typedef interface IContext IContext; -#endif /* __IContext_FWD_DEFINED__ */ - - -#ifndef __IContextMarshaler_FWD_DEFINED__ -#define __IContextMarshaler_FWD_DEFINED__ -typedef interface IContextMarshaler IContextMarshaler; -#endif /* __IContextMarshaler_FWD_DEFINED__ */ - - -#ifndef __IObjContext_FWD_DEFINED__ -#define __IObjContext_FWD_DEFINED__ -typedef interface IObjContext IObjContext; -#endif /* __IObjContext_FWD_DEFINED__ */ - - -#ifndef __IGetContextId_FWD_DEFINED__ -#define __IGetContextId_FWD_DEFINED__ -typedef interface IGetContextId IGetContextId; -#endif /* __IGetContextId_FWD_DEFINED__ */ - - -#ifndef __IAggregator_FWD_DEFINED__ -#define __IAggregator_FWD_DEFINED__ -typedef interface IAggregator IAggregator; -#endif /* __IAggregator_FWD_DEFINED__ */ - - -#ifndef __ICall_FWD_DEFINED__ -#define __ICall_FWD_DEFINED__ -typedef interface ICall ICall; -#endif /* __ICall_FWD_DEFINED__ */ - - -#ifndef __IRpcCall_FWD_DEFINED__ -#define __IRpcCall_FWD_DEFINED__ -typedef interface IRpcCall IRpcCall; -#endif /* __IRpcCall_FWD_DEFINED__ */ - - -#ifndef __ICallInfo_FWD_DEFINED__ -#define __ICallInfo_FWD_DEFINED__ -typedef interface ICallInfo ICallInfo; -#endif /* __ICallInfo_FWD_DEFINED__ */ - - -#ifndef __IPolicy_FWD_DEFINED__ -#define __IPolicy_FWD_DEFINED__ -typedef interface IPolicy IPolicy; -#endif /* __IPolicy_FWD_DEFINED__ */ - - -#ifndef __IPolicyAsync_FWD_DEFINED__ -#define __IPolicyAsync_FWD_DEFINED__ -typedef interface IPolicyAsync IPolicyAsync; -#endif /* __IPolicyAsync_FWD_DEFINED__ */ - - -#ifndef __IPolicySet_FWD_DEFINED__ -#define __IPolicySet_FWD_DEFINED__ -typedef interface IPolicySet IPolicySet; -#endif /* __IPolicySet_FWD_DEFINED__ */ - - -#ifndef __IComObjIdentity_FWD_DEFINED__ -#define __IComObjIdentity_FWD_DEFINED__ -typedef interface IComObjIdentity IComObjIdentity; -#endif /* __IComObjIdentity_FWD_DEFINED__ */ - - -#ifndef __IPolicyMaker_FWD_DEFINED__ -#define __IPolicyMaker_FWD_DEFINED__ -typedef interface IPolicyMaker IPolicyMaker; -#endif /* __IPolicyMaker_FWD_DEFINED__ */ - - -#ifndef __IExceptionNotification_FWD_DEFINED__ -#define __IExceptionNotification_FWD_DEFINED__ -typedef interface IExceptionNotification IExceptionNotification; -#endif /* __IExceptionNotification_FWD_DEFINED__ */ - - -#ifndef __IMarshalEnvoy_FWD_DEFINED__ -#define __IMarshalEnvoy_FWD_DEFINED__ -typedef interface IMarshalEnvoy IMarshalEnvoy; -#endif /* __IMarshalEnvoy_FWD_DEFINED__ */ - - -#ifndef __IWrapperInfo_FWD_DEFINED__ -#define __IWrapperInfo_FWD_DEFINED__ -typedef interface IWrapperInfo IWrapperInfo; -#endif /* __IWrapperInfo_FWD_DEFINED__ */ - - -#ifndef __IComThreadingInfo_FWD_DEFINED__ -#define __IComThreadingInfo_FWD_DEFINED__ -typedef interface IComThreadingInfo IComThreadingInfo; -#endif /* __IComThreadingInfo_FWD_DEFINED__ */ - - -#ifndef __IComDispatchInfo_FWD_DEFINED__ -#define __IComDispatchInfo_FWD_DEFINED__ -typedef interface IComDispatchInfo IComDispatchInfo; -#endif /* __IComDispatchInfo_FWD_DEFINED__ */ - - -/* header files for imported files */ -#include "wtypes.h" -#include "objidl.h" - -void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t); -void __RPC_USER MIDL_user_free( void __RPC_FAR * ); - -/* interface __MIDL_itf_contxt_0000 */ -/* [local] */ - -enum tagCONTEXTEVENT - { CONTEXTEVENT_NONE = 0, - CONTEXTEVENT_CALL = 0x1, - CONTEXTEVENT_ENTER = 0x2, - CONTEXTEVENT_LEAVE = 0x4, - CONTEXTEVENT_RETURN = 0x8, - CONTEXTEVENT_CALLFILLBUFFER = 0x10, - CONTEXTEVENT_ENTERWITHBUFFER = 0x20, - CONTEXTEVENT_LEAVEFILLBUFFER = 0x40, - CONTEXTEVENT_RETURNWITHBUFFER = 0x80, - CONTEXTEVENT_BEGINCALL = 0x100, - CONTEXTEVENT_BEGINENTER = 0x200, - CONTEXTEVENT_BEGINLEAVE = 0x400, - CONTEXTEVENT_BEGINRETURN = 0x800, - CONTEXTEVENT_FINISHCALL = 0x1000, - CONTEXTEVENT_FINISHENTER = 0x2000, - CONTEXTEVENT_FINISHLEAVE = 0x4000, - CONTEXTEVENT_FINISHRETURN = 0x8000, - CONTEXTEVENT_BEGINCALLFILLBUFFER = 0x10000, - CONTEXTEVENT_BEGINENTERWITHBUFFER = 0x20000, - CONTEXTEVENT_FINISHLEAVEFILLBUFFER = 0x40000, - CONTEXTEVENT_FINISHRETURNWITHBUFFER = 0x80000, - CONTEXTEVENT_LEAVEEXCEPTION = 0x100000, - CONTEXTEVENT_LEAVEEXCEPTIONFILLBUFFER = 0x200000, - CONTEXTEVENT_RETURNEXCEPTION = 0x400000, - CONTEXTEVENT_RETURNEXCEPTIONWITHBUFFER = 0x800000, - CONTEXTEVENT_ADDREFPOLICY = 0x10000000, - CONTEXTEVENT_RELEASEPOLICY = 0x20000000 - }; -typedef DWORD ContextEvent; - - -enum tagCPFLAGS - { CPFLAG_NONE = 0, - CPFLAG_PROPAGATE = 0x1, - CPFLAG_EXPOSE = 0x2, - CPFLAG_ENVOY = 0x4, - CPFLAG_MONITORSTUB = 0x8, - CPFLAG_MONITORPROXY = 0x10, - CPFLAG_DONTCOMPARE = 0x20 - }; -typedef DWORD CPFLAGS; - -extern RPC_IF_HANDLE __MIDL_itf_contxt_0000_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_contxt_0000_v0_0_s_ifspec; - -#ifndef __IEnumContextProps_INTERFACE_DEFINED__ -#define __IEnumContextProps_INTERFACE_DEFINED__ - -/* interface IEnumContextProps */ -/* [unique][uuid][object] */ - -typedef /* [unique] */ IEnumContextProps __RPC_FAR *LPENUMCONTEXTPROPS; - - -EXTERN_C const IID IID_IEnumContextProps; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c1-0000-0000-C000-000000000046") - IEnumContextProps : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE Next( - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ ContextProperty __RPC_FAR *pContextProperties, - /* [out] */ ULONG __RPC_FAR *pceltFetched) = 0; - - virtual HRESULT STDMETHODCALLTYPE Skip( - /* [in] */ ULONG celt) = 0; - - virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE Clone( - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps) = 0; - - virtual HRESULT STDMETHODCALLTYPE Count( - /* [out] */ ULONG __RPC_FAR *pcelt) = 0; - - }; - -#else /* C style interface */ - - typedef struct IEnumContextPropsVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IEnumContextProps __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IEnumContextProps __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IEnumContextProps __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Next )( - IEnumContextProps __RPC_FAR * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ ContextProperty __RPC_FAR *pContextProperties, - /* [out] */ ULONG __RPC_FAR *pceltFetched); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Skip )( - IEnumContextProps __RPC_FAR * This, - /* [in] */ ULONG celt); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Reset )( - IEnumContextProps __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Clone )( - IEnumContextProps __RPC_FAR * This, - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Count )( - IEnumContextProps __RPC_FAR * This, - /* [out] */ ULONG __RPC_FAR *pcelt); - - END_INTERFACE - } IEnumContextPropsVtbl; - - interface IEnumContextProps - { - CONST_VTBL struct IEnumContextPropsVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IEnumContextProps_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IEnumContextProps_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IEnumContextProps_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IEnumContextProps_Next(This,celt,pContextProperties,pceltFetched) \ - (This)->lpVtbl -> Next(This,celt,pContextProperties,pceltFetched) - -#define IEnumContextProps_Skip(This,celt) \ - (This)->lpVtbl -> Skip(This,celt) - -#define IEnumContextProps_Reset(This) \ - (This)->lpVtbl -> Reset(This) - -#define IEnumContextProps_Clone(This,ppEnumContextProps) \ - (This)->lpVtbl -> Clone(This,ppEnumContextProps) - -#define IEnumContextProps_Count(This,pcelt) \ - (This)->lpVtbl -> Count(This,pcelt) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IEnumContextProps_Next_Proxy( - IEnumContextProps __RPC_FAR * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ ContextProperty __RPC_FAR *pContextProperties, - /* [out] */ ULONG __RPC_FAR *pceltFetched); - - -void __RPC_STUB IEnumContextProps_Next_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IEnumContextProps_Skip_Proxy( - IEnumContextProps __RPC_FAR * This, - /* [in] */ ULONG celt); - - -void __RPC_STUB IEnumContextProps_Skip_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IEnumContextProps_Reset_Proxy( - IEnumContextProps __RPC_FAR * This); - - -void __RPC_STUB IEnumContextProps_Reset_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IEnumContextProps_Clone_Proxy( - IEnumContextProps __RPC_FAR * This, - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps); - - -void __RPC_STUB IEnumContextProps_Clone_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IEnumContextProps_Count_Proxy( - IEnumContextProps __RPC_FAR * This, - /* [out] */ ULONG __RPC_FAR *pcelt); - - -void __RPC_STUB IEnumContextProps_Count_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IEnumContextProps_INTERFACE_DEFINED__ */ - - -#ifndef __IContext_INTERFACE_DEFINED__ -#define __IContext_INTERFACE_DEFINED__ - -/* interface IContext */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IContext; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c0-0000-0000-C000-000000000046") - IContext : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE SetProperty( - /* [in] */ REFGUID rpolicyId, - /* [in] */ CPFLAGS flags, - /* [in] */ IUnknown __RPC_FAR *pUnk) = 0; - - virtual HRESULT STDMETHODCALLTYPE RemoveProperty( - /* [in] */ REFGUID rPolicyId) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetProperty( - /* [in] */ REFGUID rGuid, - /* [out] */ CPFLAGS __RPC_FAR *pFlags, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk) = 0; - - virtual HRESULT STDMETHODCALLTYPE EnumContextProps( - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps) = 0; - - }; - -#else /* C style interface */ - - typedef struct IContextVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IContext __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IContext __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IContext __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetProperty )( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rpolicyId, - /* [in] */ CPFLAGS flags, - /* [in] */ IUnknown __RPC_FAR *pUnk); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *RemoveProperty )( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rPolicyId); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetProperty )( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rGuid, - /* [out] */ CPFLAGS __RPC_FAR *pFlags, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *EnumContextProps )( - IContext __RPC_FAR * This, - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps); - - END_INTERFACE - } IContextVtbl; - - interface IContext - { - CONST_VTBL struct IContextVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IContext_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IContext_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IContext_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IContext_SetProperty(This,rpolicyId,flags,pUnk) \ - (This)->lpVtbl -> SetProperty(This,rpolicyId,flags,pUnk) - -#define IContext_RemoveProperty(This,rPolicyId) \ - (This)->lpVtbl -> RemoveProperty(This,rPolicyId) - -#define IContext_GetProperty(This,rGuid,pFlags,ppUnk) \ - (This)->lpVtbl -> GetProperty(This,rGuid,pFlags,ppUnk) - -#define IContext_EnumContextProps(This,ppEnumContextProps) \ - (This)->lpVtbl -> EnumContextProps(This,ppEnumContextProps) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IContext_SetProperty_Proxy( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rpolicyId, - /* [in] */ CPFLAGS flags, - /* [in] */ IUnknown __RPC_FAR *pUnk); - - -void __RPC_STUB IContext_SetProperty_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IContext_RemoveProperty_Proxy( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rPolicyId); - - -void __RPC_STUB IContext_RemoveProperty_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IContext_GetProperty_Proxy( - IContext __RPC_FAR * This, - /* [in] */ REFGUID rGuid, - /* [out] */ CPFLAGS __RPC_FAR *pFlags, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk); - - -void __RPC_STUB IContext_GetProperty_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IContext_EnumContextProps_Proxy( - IContext __RPC_FAR * This, - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps); - - -void __RPC_STUB IContext_EnumContextProps_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IContext_INTERFACE_DEFINED__ */ - - -#ifndef __IContextMarshaler_INTERFACE_DEFINED__ -#define __IContextMarshaler_INTERFACE_DEFINED__ - -/* interface IContextMarshaler */ -/* [uuid][object][local] */ - -typedef /* [unique] */ IContextMarshaler __RPC_FAR *LPCTXMARSHALER; - - -EXTERN_C const IID IID_IContextMarshaler; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001D8-0000-0000-C000-000000000046") - IContextMarshaler : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetMarshalSizeMax( - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags, - /* [out] */ DWORD __RPC_FAR *pSize) = 0; - - virtual HRESULT STDMETHODCALLTYPE MarshalInterface( - /* [unique][in] */ IStream __RPC_FAR *pStm, - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags) = 0; - - }; - -#else /* C style interface */ - - typedef struct IContextMarshalerVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IContextMarshaler __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IContextMarshaler __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IContextMarshaler __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetMarshalSizeMax )( - IContextMarshaler __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags, - /* [out] */ DWORD __RPC_FAR *pSize); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *MarshalInterface )( - IContextMarshaler __RPC_FAR * This, - /* [unique][in] */ IStream __RPC_FAR *pStm, - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags); - - END_INTERFACE - } IContextMarshalerVtbl; - - interface IContextMarshaler - { - CONST_VTBL struct IContextMarshalerVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IContextMarshaler_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IContextMarshaler_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IContextMarshaler_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IContextMarshaler_GetMarshalSizeMax(This,riid,pv,dwDestContext,pvDestContext,mshlflags,pSize) \ - (This)->lpVtbl -> GetMarshalSizeMax(This,riid,pv,dwDestContext,pvDestContext,mshlflags,pSize) - -#define IContextMarshaler_MarshalInterface(This,pStm,riid,pv,dwDestContext,pvDestContext,mshlflags) \ - (This)->lpVtbl -> MarshalInterface(This,pStm,riid,pv,dwDestContext,pvDestContext,mshlflags) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IContextMarshaler_GetMarshalSizeMax_Proxy( - IContextMarshaler __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags, - /* [out] */ DWORD __RPC_FAR *pSize); - - -void __RPC_STUB IContextMarshaler_GetMarshalSizeMax_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IContextMarshaler_MarshalInterface_Proxy( - IContextMarshaler __RPC_FAR * This, - /* [unique][in] */ IStream __RPC_FAR *pStm, - /* [in] */ REFIID riid, - /* [unique][in] */ void __RPC_FAR *pv, - /* [in] */ DWORD dwDestContext, - /* [unique][in] */ void __RPC_FAR *pvDestContext, - /* [in] */ DWORD mshlflags); - - -void __RPC_STUB IContextMarshaler_MarshalInterface_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IContextMarshaler_INTERFACE_DEFINED__ */ - - -// Placing the following definition here rather than with the IObjContext stuff -// below is a temporary workaround to get around build problems where the system -// objidl.h now has a IObjContext section but has not made much public (all the -// interface methods are marked as reserved and the following typedef does not -// exist). Once the system objidl.h is updated again we can remove the entire -// section. -#ifndef __PFNCTXCALLBACK_HACK -#define __PFNCTXCALLBACK_HACK -typedef /* [ref] */ HRESULT ( __stdcall __RPC_FAR *PFNCTXCALLBACK )( - void __RPC_FAR *pParam); -#endif - -#ifndef __IObjContext_INTERFACE_DEFINED__ -#define __IObjContext_INTERFACE_DEFINED__ - -/* interface IObjContext */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IObjContext; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c6-0000-0000-C000-000000000046") - IObjContext : public IContext - { - public: - virtual HRESULT STDMETHODCALLTYPE Freeze( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE DoCallback( - /* [in] */ PFNCTXCALLBACK pfnCallback, - /* [in] */ void __RPC_FAR *pParam, - /* [in] */ REFIID riid, - /* [in] */ unsigned int iMethod) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetContextMarshaler( - /* [in] */ IContextMarshaler __RPC_FAR *pICM) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetContextMarshaler( - /* [out] */ IContextMarshaler __RPC_FAR *__RPC_FAR *pICM) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetContextFlags( - /* [in] */ DWORD dwFlags) = 0; - - virtual HRESULT STDMETHODCALLTYPE ClearContextFlags( - /* [in] */ DWORD dwFlags) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetContextFlags( - /* [out] */ DWORD __RPC_FAR *pdwFlags) = 0; - - }; - -#else /* C style interface */ - - typedef struct IObjContextVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IObjContext __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IObjContext __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IObjContext __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetProperty )( - IObjContext __RPC_FAR * This, - /* [in] */ REFGUID rpolicyId, - /* [in] */ CPFLAGS flags, - /* [in] */ IUnknown __RPC_FAR *pUnk); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *RemoveProperty )( - IObjContext __RPC_FAR * This, - /* [in] */ REFGUID rPolicyId); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetProperty )( - IObjContext __RPC_FAR * This, - /* [in] */ REFGUID rGuid, - /* [out] */ CPFLAGS __RPC_FAR *pFlags, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *EnumContextProps )( - IObjContext __RPC_FAR * This, - /* [out] */ IEnumContextProps __RPC_FAR *__RPC_FAR *ppEnumContextProps); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Freeze )( - IObjContext __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *DoCallback )( - IObjContext __RPC_FAR * This, - /* [in] */ PFNCTXCALLBACK pfnCallback, - /* [in] */ void __RPC_FAR *pParam, - /* [in] */ REFIID riid, - /* [in] */ unsigned int iMethod); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetContextMarshaler )( - IObjContext __RPC_FAR * This, - /* [in] */ IContextMarshaler __RPC_FAR *pICM); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetContextMarshaler )( - IObjContext __RPC_FAR * This, - /* [out] */ IContextMarshaler __RPC_FAR *__RPC_FAR *pICM); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetContextFlags )( - IObjContext __RPC_FAR * This, - /* [in] */ DWORD dwFlags); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *ClearContextFlags )( - IObjContext __RPC_FAR * This, - /* [in] */ DWORD dwFlags); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetContextFlags )( - IObjContext __RPC_FAR * This, - /* [out] */ DWORD __RPC_FAR *pdwFlags); - - END_INTERFACE - } IObjContextVtbl; - - interface IObjContext - { - CONST_VTBL struct IObjContextVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IObjContext_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IObjContext_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IObjContext_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IObjContext_SetProperty(This,rpolicyId,flags,pUnk) \ - (This)->lpVtbl -> SetProperty(This,rpolicyId,flags,pUnk) - -#define IObjContext_RemoveProperty(This,rPolicyId) \ - (This)->lpVtbl -> RemoveProperty(This,rPolicyId) - -#define IObjContext_GetProperty(This,rGuid,pFlags,ppUnk) \ - (This)->lpVtbl -> GetProperty(This,rGuid,pFlags,ppUnk) - -#define IObjContext_EnumContextProps(This,ppEnumContextProps) \ - (This)->lpVtbl -> EnumContextProps(This,ppEnumContextProps) - - -#define IObjContext_Freeze(This) \ - (This)->lpVtbl -> Freeze(This) - -#define IObjContext_DoCallback(This,pfnCallback,pParam,riid,iMethod) \ - (This)->lpVtbl -> DoCallback(This,pfnCallback,pParam,riid,iMethod) - -#define IObjContext_SetContextMarshaler(This,pICM) \ - (This)->lpVtbl -> SetContextMarshaler(This,pICM) - -#define IObjContext_GetContextMarshaler(This,pICM) \ - (This)->lpVtbl -> GetContextMarshaler(This,pICM) - -#define IObjContext_SetContextFlags(This,dwFlags) \ - (This)->lpVtbl -> SetContextFlags(This,dwFlags) - -#define IObjContext_ClearContextFlags(This,dwFlags) \ - (This)->lpVtbl -> ClearContextFlags(This,dwFlags) - -#define IObjContext_GetContextFlags(This,pdwFlags) \ - (This)->lpVtbl -> GetContextFlags(This,pdwFlags) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IObjContext_Freeze_Proxy( - IObjContext __RPC_FAR * This); - - -void __RPC_STUB IObjContext_Freeze_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_DoCallback_Proxy( - IObjContext __RPC_FAR * This, - /* [in] */ PFNCTXCALLBACK pfnCallback, - /* [in] */ void __RPC_FAR *pParam, - /* [in] */ REFIID riid, - /* [in] */ unsigned int iMethod); - - -void __RPC_STUB IObjContext_DoCallback_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_SetContextMarshaler_Proxy( - IObjContext __RPC_FAR * This, - /* [in] */ IContextMarshaler __RPC_FAR *pICM); - - -void __RPC_STUB IObjContext_SetContextMarshaler_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_GetContextMarshaler_Proxy( - IObjContext __RPC_FAR * This, - /* [out] */ IContextMarshaler __RPC_FAR *__RPC_FAR *pICM); - - -void __RPC_STUB IObjContext_GetContextMarshaler_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_SetContextFlags_Proxy( - IObjContext __RPC_FAR * This, - /* [in] */ DWORD dwFlags); - - -void __RPC_STUB IObjContext_SetContextFlags_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_ClearContextFlags_Proxy( - IObjContext __RPC_FAR * This, - /* [in] */ DWORD dwFlags); - - -void __RPC_STUB IObjContext_ClearContextFlags_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IObjContext_GetContextFlags_Proxy( - IObjContext __RPC_FAR * This, - /* [out] */ DWORD __RPC_FAR *pdwFlags); - - -void __RPC_STUB IObjContext_GetContextFlags_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IObjContext_INTERFACE_DEFINED__ */ - - -#ifndef __IGetContextId_INTERFACE_DEFINED__ -#define __IGetContextId_INTERFACE_DEFINED__ - -/* interface IGetContextId */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IGetContextId; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001dd-0000-0000-C000-000000000046") - IGetContextId : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetContextId( - /* [out] */ GUID __RPC_FAR *pguidCtxtId) = 0; - - }; - -#else /* C style interface */ - - typedef struct IGetContextIdVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IGetContextId __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IGetContextId __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IGetContextId __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetContextId )( - IGetContextId __RPC_FAR * This, - /* [out] */ GUID __RPC_FAR *pguidCtxtId); - - END_INTERFACE - } IGetContextIdVtbl; - - interface IGetContextId - { - CONST_VTBL struct IGetContextIdVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IGetContextId_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IGetContextId_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IGetContextId_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IGetContextId_GetContextId(This,pguidCtxtId) \ - (This)->lpVtbl -> GetContextId(This,pguidCtxtId) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IGetContextId_GetContextId_Proxy( - IGetContextId __RPC_FAR * This, - /* [out] */ GUID __RPC_FAR *pguidCtxtId); - - -void __RPC_STUB IGetContextId_GetContextId_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IGetContextId_INTERFACE_DEFINED__ */ - - -#ifndef __IAggregator_INTERFACE_DEFINED__ -#define __IAggregator_INTERFACE_DEFINED__ - -/* interface IAggregator */ -/* [unique][uuid][object][local] */ - -typedef /* [unique] */ IAggregator __RPC_FAR *IAGGREGATOR; - - -EXTERN_C const IID IID_IAggregator; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001d8-0000-0000-C000-000000000046") - IAggregator : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE Aggregate( - /* [in] */ IUnknown __RPC_FAR *pInnerUnk) = 0; - - }; - -#else /* C style interface */ - - typedef struct IAggregatorVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IAggregator __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IAggregator __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IAggregator __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Aggregate )( - IAggregator __RPC_FAR * This, - /* [in] */ IUnknown __RPC_FAR *pInnerUnk); - - END_INTERFACE - } IAggregatorVtbl; - - interface IAggregator - { - CONST_VTBL struct IAggregatorVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IAggregator_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IAggregator_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IAggregator_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IAggregator_Aggregate(This,pInnerUnk) \ - (This)->lpVtbl -> Aggregate(This,pInnerUnk) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IAggregator_Aggregate_Proxy( - IAggregator __RPC_FAR * This, - /* [in] */ IUnknown __RPC_FAR *pInnerUnk); - - -void __RPC_STUB IAggregator_Aggregate_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IAggregator_INTERFACE_DEFINED__ */ - - -#ifndef __ICall_INTERFACE_DEFINED__ -#define __ICall_INTERFACE_DEFINED__ - -/* interface ICall */ -/* [unique][uuid][object][local] */ - -typedef /* [unique] */ ICall __RPC_FAR *LPCALL; - - -EXTERN_C const IID IID_ICall; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001d6-0000-0000-C000-000000000046") - ICall : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetCallInfo( - /* [out] */ const void __RPC_FAR *__RPC_FAR *ppIdentity, - /* [out] */ IID __RPC_FAR *piid, - /* [out] */ DWORD __RPC_FAR *pdwMethod, - /* [out] */ HRESULT __RPC_FAR *phr) = 0; - - virtual HRESULT STDMETHODCALLTYPE Nullify( - /* [in] */ HRESULT hr) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetServerHR( - /* [out] */ HRESULT __RPC_FAR *phr) = 0; - - }; - -#else /* C style interface */ - - typedef struct ICallVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - ICall __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - ICall __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - ICall __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetCallInfo )( - ICall __RPC_FAR * This, - /* [out] */ const void __RPC_FAR *__RPC_FAR *ppIdentity, - /* [out] */ IID __RPC_FAR *piid, - /* [out] */ DWORD __RPC_FAR *pdwMethod, - /* [out] */ HRESULT __RPC_FAR *phr); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Nullify )( - ICall __RPC_FAR * This, - /* [in] */ HRESULT hr); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetServerHR )( - ICall __RPC_FAR * This, - /* [out] */ HRESULT __RPC_FAR *phr); - - END_INTERFACE - } ICallVtbl; - - interface ICall - { - CONST_VTBL struct ICallVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define ICall_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define ICall_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define ICall_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define ICall_GetCallInfo(This,ppIdentity,piid,pdwMethod,phr) \ - (This)->lpVtbl -> GetCallInfo(This,ppIdentity,piid,pdwMethod,phr) - -#define ICall_Nullify(This,hr) \ - (This)->lpVtbl -> Nullify(This,hr) - -#define ICall_GetServerHR(This,phr) \ - (This)->lpVtbl -> GetServerHR(This,phr) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE ICall_GetCallInfo_Proxy( - ICall __RPC_FAR * This, - /* [out] */ const void __RPC_FAR *__RPC_FAR *ppIdentity, - /* [out] */ IID __RPC_FAR *piid, - /* [out] */ DWORD __RPC_FAR *pdwMethod, - /* [out] */ HRESULT __RPC_FAR *phr); - - -void __RPC_STUB ICall_GetCallInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE ICall_Nullify_Proxy( - ICall __RPC_FAR * This, - /* [in] */ HRESULT hr); - - -void __RPC_STUB ICall_Nullify_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE ICall_GetServerHR_Proxy( - ICall __RPC_FAR * This, - /* [out] */ HRESULT __RPC_FAR *phr); - - -void __RPC_STUB ICall_GetServerHR_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __ICall_INTERFACE_DEFINED__ */ - - -#ifndef __IRpcCall_INTERFACE_DEFINED__ -#define __IRpcCall_INTERFACE_DEFINED__ - -/* interface IRpcCall */ -/* [unique][uuid][object][local] */ - -typedef /* [unique] */ IRpcCall __RPC_FAR *LPRPCCALL; - - -EXTERN_C const IID IID_IRpcCall; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c5-0000-0000-C000-000000000046") - IRpcCall : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetRpcOleMessage( - /* [out] */ RPCOLEMESSAGE __RPC_FAR *__RPC_FAR *ppMessage) = 0; - - }; - -#else /* C style interface */ - - typedef struct IRpcCallVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IRpcCall __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IRpcCall __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IRpcCall __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetRpcOleMessage )( - IRpcCall __RPC_FAR * This, - /* [out] */ RPCOLEMESSAGE __RPC_FAR *__RPC_FAR *ppMessage); - - END_INTERFACE - } IRpcCallVtbl; - - interface IRpcCall - { - CONST_VTBL struct IRpcCallVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IRpcCall_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IRpcCall_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IRpcCall_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IRpcCall_GetRpcOleMessage(This,ppMessage) \ - (This)->lpVtbl -> GetRpcOleMessage(This,ppMessage) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IRpcCall_GetRpcOleMessage_Proxy( - IRpcCall __RPC_FAR * This, - /* [out] */ RPCOLEMESSAGE __RPC_FAR *__RPC_FAR *ppMessage); - - -void __RPC_STUB IRpcCall_GetRpcOleMessage_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IRpcCall_INTERFACE_DEFINED__ */ - - -/* interface __MIDL_itf_contxt_0083 */ -/* [local] */ - -typedef -enum _CALLSOURCE - { CALLSOURCE_CROSSAPT = 0, - CALLSOURCE_CROSSCTX = 1 - } CALLSOURCE; - - - -extern RPC_IF_HANDLE __MIDL_itf_contxt_0083_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_contxt_0083_v0_0_s_ifspec; - -#ifndef __ICallInfo_INTERFACE_DEFINED__ -#define __ICallInfo_INTERFACE_DEFINED__ - -/* interface ICallInfo */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_ICallInfo; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001dc-0000-0000-C000-000000000046") - ICallInfo : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetCallSource( - /* [out] */ CALLSOURCE __RPC_FAR *pCallSource) = 0; - - }; - -#else /* C style interface */ - - typedef struct ICallInfoVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - ICallInfo __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - ICallInfo __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - ICallInfo __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetCallSource )( - ICallInfo __RPC_FAR * This, - /* [out] */ CALLSOURCE __RPC_FAR *pCallSource); - - END_INTERFACE - } ICallInfoVtbl; - - interface ICallInfo - { - CONST_VTBL struct ICallInfoVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define ICallInfo_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define ICallInfo_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define ICallInfo_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define ICallInfo_GetCallSource(This,pCallSource) \ - (This)->lpVtbl -> GetCallSource(This,pCallSource) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE ICallInfo_GetCallSource_Proxy( - ICallInfo __RPC_FAR * This, - /* [out] */ CALLSOURCE __RPC_FAR *pCallSource); - - -void __RPC_STUB ICallInfo_GetCallSource_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __ICallInfo_INTERFACE_DEFINED__ */ - - -#ifndef __IPolicy_INTERFACE_DEFINED__ -#define __IPolicy_INTERFACE_DEFINED__ - -/* interface IPolicy */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IPolicy; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c2-0000-0000-C000-000000000046") - IPolicy : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE Call( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE Enter( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE Leave( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE Return( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE CallGetSize( - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE CallFillBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE EnterWithBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb) = 0; - - virtual HRESULT STDMETHODCALLTYPE LeaveGetSize( - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE LeaveFillBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE ReturnWithBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb) = 0; - - virtual ULONG STDMETHODCALLTYPE AddRefPolicy( void) = 0; - - virtual ULONG STDMETHODCALLTYPE ReleasePolicy( void) = 0; - - }; - -#else /* C style interface */ - - typedef struct IPolicyVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IPolicy __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IPolicy __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IPolicy __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Call )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Enter )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Leave )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Return )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CallGetSize )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CallFillBuffer )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *EnterWithBuffer )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *LeaveGetSize )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *LeaveFillBuffer )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *ReturnWithBuffer )( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRefPolicy )( - IPolicy __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *ReleasePolicy )( - IPolicy __RPC_FAR * This); - - END_INTERFACE - } IPolicyVtbl; - - interface IPolicy - { - CONST_VTBL struct IPolicyVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IPolicy_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IPolicy_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IPolicy_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IPolicy_Call(This,pCall) \ - (This)->lpVtbl -> Call(This,pCall) - -#define IPolicy_Enter(This,pCall) \ - (This)->lpVtbl -> Enter(This,pCall) - -#define IPolicy_Leave(This,pCall) \ - (This)->lpVtbl -> Leave(This,pCall) - -#define IPolicy_Return(This,pCall) \ - (This)->lpVtbl -> Return(This,pCall) - -#define IPolicy_CallGetSize(This,pCall,pcb) \ - (This)->lpVtbl -> CallGetSize(This,pCall,pcb) - -#define IPolicy_CallFillBuffer(This,pCall,pvBuf,pcb) \ - (This)->lpVtbl -> CallFillBuffer(This,pCall,pvBuf,pcb) - -#define IPolicy_EnterWithBuffer(This,pCall,pvBuf,cb) \ - (This)->lpVtbl -> EnterWithBuffer(This,pCall,pvBuf,cb) - -#define IPolicy_LeaveGetSize(This,pCall,pcb) \ - (This)->lpVtbl -> LeaveGetSize(This,pCall,pcb) - -#define IPolicy_LeaveFillBuffer(This,pCall,pvBuf,pcb) \ - (This)->lpVtbl -> LeaveFillBuffer(This,pCall,pvBuf,pcb) - -#define IPolicy_ReturnWithBuffer(This,pCall,pvBuf,cb) \ - (This)->lpVtbl -> ReturnWithBuffer(This,pCall,pvBuf,cb) - -#define IPolicy_AddRefPolicy(This) \ - (This)->lpVtbl -> AddRefPolicy(This) - -#define IPolicy_ReleasePolicy(This) \ - (This)->lpVtbl -> ReleasePolicy(This) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IPolicy_Call_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicy_Call_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_Enter_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicy_Enter_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_Leave_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicy_Leave_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_Return_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicy_Return_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_CallGetSize_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicy_CallGetSize_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_CallFillBuffer_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicy_CallFillBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_EnterWithBuffer_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - -void __RPC_STUB IPolicy_EnterWithBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_LeaveGetSize_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicy_LeaveGetSize_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_LeaveFillBuffer_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicy_LeaveFillBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicy_ReturnWithBuffer_Proxy( - IPolicy __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - -void __RPC_STUB IPolicy_ReturnWithBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -ULONG STDMETHODCALLTYPE IPolicy_AddRefPolicy_Proxy( - IPolicy __RPC_FAR * This); - - -void __RPC_STUB IPolicy_AddRefPolicy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -ULONG STDMETHODCALLTYPE IPolicy_ReleasePolicy_Proxy( - IPolicy __RPC_FAR * This); - - -void __RPC_STUB IPolicy_ReleasePolicy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IPolicy_INTERFACE_DEFINED__ */ - - -#ifndef __IPolicyAsync_INTERFACE_DEFINED__ -#define __IPolicyAsync_INTERFACE_DEFINED__ - -/* interface IPolicyAsync */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IPolicyAsync; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001cd-0000-0000-C000-000000000046") - IPolicyAsync : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE BeginCallGetSize( - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginCall( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginCallFillBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginEnter( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginEnterWithBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginLeave( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE BeginReturn( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishCall( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishEnter( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishLeaveGetSize( - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishLeave( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishLeaveFillBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishReturn( - /* [in] */ ICall __RPC_FAR *pCall) = 0; - - virtual HRESULT STDMETHODCALLTYPE FinishReturnWithBuffer( - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb) = 0; - - }; - -#else /* C style interface */ - - typedef struct IPolicyAsyncVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IPolicyAsync __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IPolicyAsync __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginCallGetSize )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginCall )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginCallFillBuffer )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginEnter )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginEnterWithBuffer )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginLeave )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginReturn )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishCall )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishEnter )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishLeaveGetSize )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishLeave )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishLeaveFillBuffer )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishReturn )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *FinishReturnWithBuffer )( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - END_INTERFACE - } IPolicyAsyncVtbl; - - interface IPolicyAsync - { - CONST_VTBL struct IPolicyAsyncVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IPolicyAsync_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IPolicyAsync_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IPolicyAsync_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IPolicyAsync_BeginCallGetSize(This,pCall,pcb) \ - (This)->lpVtbl -> BeginCallGetSize(This,pCall,pcb) - -#define IPolicyAsync_BeginCall(This,pCall) \ - (This)->lpVtbl -> BeginCall(This,pCall) - -#define IPolicyAsync_BeginCallFillBuffer(This,pCall,pvBuf,pcb) \ - (This)->lpVtbl -> BeginCallFillBuffer(This,pCall,pvBuf,pcb) - -#define IPolicyAsync_BeginEnter(This,pCall) \ - (This)->lpVtbl -> BeginEnter(This,pCall) - -#define IPolicyAsync_BeginEnterWithBuffer(This,pCall,pvBuf,cb) \ - (This)->lpVtbl -> BeginEnterWithBuffer(This,pCall,pvBuf,cb) - -#define IPolicyAsync_BeginLeave(This,pCall) \ - (This)->lpVtbl -> BeginLeave(This,pCall) - -#define IPolicyAsync_BeginReturn(This,pCall) \ - (This)->lpVtbl -> BeginReturn(This,pCall) - -#define IPolicyAsync_FinishCall(This,pCall) \ - (This)->lpVtbl -> FinishCall(This,pCall) - -#define IPolicyAsync_FinishEnter(This,pCall) \ - (This)->lpVtbl -> FinishEnter(This,pCall) - -#define IPolicyAsync_FinishLeaveGetSize(This,pCall,pcb) \ - (This)->lpVtbl -> FinishLeaveGetSize(This,pCall,pcb) - -#define IPolicyAsync_FinishLeave(This,pCall) \ - (This)->lpVtbl -> FinishLeave(This,pCall) - -#define IPolicyAsync_FinishLeaveFillBuffer(This,pCall,pvBuf,pcb) \ - (This)->lpVtbl -> FinishLeaveFillBuffer(This,pCall,pvBuf,pcb) - -#define IPolicyAsync_FinishReturn(This,pCall) \ - (This)->lpVtbl -> FinishReturn(This,pCall) - -#define IPolicyAsync_FinishReturnWithBuffer(This,pCall,pvBuf,cb) \ - (This)->lpVtbl -> FinishReturnWithBuffer(This,pCall,pvBuf,cb) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginCallGetSize_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicyAsync_BeginCallGetSize_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginCall_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_BeginCall_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginCallFillBuffer_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicyAsync_BeginCallFillBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginEnter_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_BeginEnter_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginEnterWithBuffer_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - -void __RPC_STUB IPolicyAsync_BeginEnterWithBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginLeave_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_BeginLeave_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_BeginReturn_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_BeginReturn_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishCall_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_FinishCall_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishEnter_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_FinishEnter_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishLeaveGetSize_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicyAsync_FinishLeaveGetSize_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishLeave_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_FinishLeave_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishLeaveFillBuffer_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [out] */ ULONG __RPC_FAR *pcb); - - -void __RPC_STUB IPolicyAsync_FinishLeaveFillBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishReturn_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall); - - -void __RPC_STUB IPolicyAsync_FinishReturn_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyAsync_FinishReturnWithBuffer_Proxy( - IPolicyAsync __RPC_FAR * This, - /* [in] */ ICall __RPC_FAR *pCall, - /* [in] */ void __RPC_FAR *pvBuf, - /* [in] */ ULONG cb); - - -void __RPC_STUB IPolicyAsync_FinishReturnWithBuffer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IPolicyAsync_INTERFACE_DEFINED__ */ - - -#ifndef __IPolicySet_INTERFACE_DEFINED__ -#define __IPolicySet_INTERFACE_DEFINED__ - -/* interface IPolicySet */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IPolicySet; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c3-0000-0000-C000-000000000046") - IPolicySet : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE AddPolicy( - /* [in] */ ContextEvent ctxEvent, - /* [in] */ REFGUID rguid, - /* [in] */ IPolicy __RPC_FAR *pPolicy) = 0; - - }; - -#else /* C style interface */ - - typedef struct IPolicySetVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IPolicySet __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IPolicySet __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IPolicySet __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *AddPolicy )( - IPolicySet __RPC_FAR * This, - /* [in] */ ContextEvent ctxEvent, - /* [in] */ REFGUID rguid, - /* [in] */ IPolicy __RPC_FAR *pPolicy); - - END_INTERFACE - } IPolicySetVtbl; - - interface IPolicySet - { - CONST_VTBL struct IPolicySetVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IPolicySet_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IPolicySet_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IPolicySet_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IPolicySet_AddPolicy(This,ctxEvent,rguid,pPolicy) \ - (This)->lpVtbl -> AddPolicy(This,ctxEvent,rguid,pPolicy) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IPolicySet_AddPolicy_Proxy( - IPolicySet __RPC_FAR * This, - /* [in] */ ContextEvent ctxEvent, - /* [in] */ REFGUID rguid, - /* [in] */ IPolicy __RPC_FAR *pPolicy); - - -void __RPC_STUB IPolicySet_AddPolicy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IPolicySet_INTERFACE_DEFINED__ */ - - -#ifndef __IComObjIdentity_INTERFACE_DEFINED__ -#define __IComObjIdentity_INTERFACE_DEFINED__ - -/* interface IComObjIdentity */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IComObjIdentity; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001d7-0000-0000-C000-000000000046") - IComObjIdentity : public IUnknown - { - public: - virtual BOOL STDMETHODCALLTYPE IsServer( void) = 0; - - virtual BOOL STDMETHODCALLTYPE IsDeactivated( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetIdentity( - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk) = 0; - - }; - -#else /* C style interface */ - - typedef struct IComObjIdentityVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IComObjIdentity __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IComObjIdentity __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IComObjIdentity __RPC_FAR * This); - - BOOL ( STDMETHODCALLTYPE __RPC_FAR *IsServer )( - IComObjIdentity __RPC_FAR * This); - - BOOL ( STDMETHODCALLTYPE __RPC_FAR *IsDeactivated )( - IComObjIdentity __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetIdentity )( - IComObjIdentity __RPC_FAR * This, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk); - - END_INTERFACE - } IComObjIdentityVtbl; - - interface IComObjIdentity - { - CONST_VTBL struct IComObjIdentityVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IComObjIdentity_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IComObjIdentity_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IComObjIdentity_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IComObjIdentity_IsServer(This) \ - (This)->lpVtbl -> IsServer(This) - -#define IComObjIdentity_IsDeactivated(This) \ - (This)->lpVtbl -> IsDeactivated(This) - -#define IComObjIdentity_GetIdentity(This,ppUnk) \ - (This)->lpVtbl -> GetIdentity(This,ppUnk) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -BOOL STDMETHODCALLTYPE IComObjIdentity_IsServer_Proxy( - IComObjIdentity __RPC_FAR * This); - - -void __RPC_STUB IComObjIdentity_IsServer_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -BOOL STDMETHODCALLTYPE IComObjIdentity_IsDeactivated_Proxy( - IComObjIdentity __RPC_FAR * This); - - -void __RPC_STUB IComObjIdentity_IsDeactivated_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IComObjIdentity_GetIdentity_Proxy( - IComObjIdentity __RPC_FAR * This, - /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppUnk); - - -void __RPC_STUB IComObjIdentity_GetIdentity_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IComObjIdentity_INTERFACE_DEFINED__ */ - - -#ifndef __IPolicyMaker_INTERFACE_DEFINED__ -#define __IPolicyMaker_INTERFACE_DEFINED__ - -/* interface IPolicyMaker */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IPolicyMaker; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c4-0000-0000-C000-000000000046") - IPolicyMaker : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE AddClientPoliciesToSet( - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext) = 0; - - virtual HRESULT STDMETHODCALLTYPE AddEnvoyPoliciesToSet( - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext) = 0; - - virtual HRESULT STDMETHODCALLTYPE AddServerPoliciesToSet( - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext) = 0; - - virtual HRESULT STDMETHODCALLTYPE Freeze( - /* [in] */ IObjContext __RPC_FAR *pObjContext) = 0; - - virtual HRESULT STDMETHODCALLTYPE CreateStub( - /* [in] */ IComObjIdentity __RPC_FAR *pID) = 0; - - virtual HRESULT STDMETHODCALLTYPE DestroyStub( - /* [in] */ IComObjIdentity __RPC_FAR *pID) = 0; - - virtual HRESULT STDMETHODCALLTYPE CreateProxy( - /* [in] */ IComObjIdentity __RPC_FAR *pID) = 0; - - virtual HRESULT STDMETHODCALLTYPE DestroyProxy( - /* [in] */ IComObjIdentity __RPC_FAR *pID) = 0; - - }; - -#else /* C style interface */ - - typedef struct IPolicyMakerVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IPolicyMaker __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IPolicyMaker __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *AddClientPoliciesToSet )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *AddEnvoyPoliciesToSet )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *AddServerPoliciesToSet )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Freeze )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IObjContext __RPC_FAR *pObjContext); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CreateStub )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *DestroyStub )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CreateProxy )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *DestroyProxy )( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - END_INTERFACE - } IPolicyMakerVtbl; - - interface IPolicyMaker - { - CONST_VTBL struct IPolicyMakerVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IPolicyMaker_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IPolicyMaker_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IPolicyMaker_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IPolicyMaker_AddClientPoliciesToSet(This,pPS,pClientContext,pServerContext) \ - (This)->lpVtbl -> AddClientPoliciesToSet(This,pPS,pClientContext,pServerContext) - -#define IPolicyMaker_AddEnvoyPoliciesToSet(This,pPS,pClientContext,pServerContext) \ - (This)->lpVtbl -> AddEnvoyPoliciesToSet(This,pPS,pClientContext,pServerContext) - -#define IPolicyMaker_AddServerPoliciesToSet(This,pPS,pClientContext,pServerContext) \ - (This)->lpVtbl -> AddServerPoliciesToSet(This,pPS,pClientContext,pServerContext) - -#define IPolicyMaker_Freeze(This,pObjContext) \ - (This)->lpVtbl -> Freeze(This,pObjContext) - -#define IPolicyMaker_CreateStub(This,pID) \ - (This)->lpVtbl -> CreateStub(This,pID) - -#define IPolicyMaker_DestroyStub(This,pID) \ - (This)->lpVtbl -> DestroyStub(This,pID) - -#define IPolicyMaker_CreateProxy(This,pID) \ - (This)->lpVtbl -> CreateProxy(This,pID) - -#define IPolicyMaker_DestroyProxy(This,pID) \ - (This)->lpVtbl -> DestroyProxy(This,pID) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_AddClientPoliciesToSet_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - -void __RPC_STUB IPolicyMaker_AddClientPoliciesToSet_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_AddEnvoyPoliciesToSet_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - -void __RPC_STUB IPolicyMaker_AddEnvoyPoliciesToSet_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_AddServerPoliciesToSet_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IPolicySet __RPC_FAR *pPS, - /* [in] */ IContext __RPC_FAR *pClientContext, - /* [in] */ IContext __RPC_FAR *pServerContext); - - -void __RPC_STUB IPolicyMaker_AddServerPoliciesToSet_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_Freeze_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IObjContext __RPC_FAR *pObjContext); - - -void __RPC_STUB IPolicyMaker_Freeze_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_CreateStub_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - -void __RPC_STUB IPolicyMaker_CreateStub_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_DestroyStub_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - -void __RPC_STUB IPolicyMaker_DestroyStub_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_CreateProxy_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - -void __RPC_STUB IPolicyMaker_CreateProxy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IPolicyMaker_DestroyProxy_Proxy( - IPolicyMaker __RPC_FAR * This, - /* [in] */ IComObjIdentity __RPC_FAR *pID); - - -void __RPC_STUB IPolicyMaker_DestroyProxy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IPolicyMaker_INTERFACE_DEFINED__ */ - - -#ifndef __IExceptionNotification_INTERFACE_DEFINED__ -#define __IExceptionNotification_INTERFACE_DEFINED__ - -/* interface IExceptionNotification */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IExceptionNotification; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001db-0000-0000-C000-000000000046") - IExceptionNotification : public IUnknown - { - public: - virtual void STDMETHODCALLTYPE ServerException( - /* [in] */ void __RPC_FAR *pExcepPtrs) = 0; - - }; - -#else /* C style interface */ - - typedef struct IExceptionNotificationVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IExceptionNotification __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IExceptionNotification __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IExceptionNotification __RPC_FAR * This); - - void ( STDMETHODCALLTYPE __RPC_FAR *ServerException )( - IExceptionNotification __RPC_FAR * This, - /* [in] */ void __RPC_FAR *pExcepPtrs); - - END_INTERFACE - } IExceptionNotificationVtbl; - - interface IExceptionNotification - { - CONST_VTBL struct IExceptionNotificationVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IExceptionNotification_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IExceptionNotification_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IExceptionNotification_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IExceptionNotification_ServerException(This,pExcepPtrs) \ - (This)->lpVtbl -> ServerException(This,pExcepPtrs) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -void STDMETHODCALLTYPE IExceptionNotification_ServerException_Proxy( - IExceptionNotification __RPC_FAR * This, - /* [in] */ void __RPC_FAR *pExcepPtrs); - - -void __RPC_STUB IExceptionNotification_ServerException_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IExceptionNotification_INTERFACE_DEFINED__ */ - - -#ifndef __IMarshalEnvoy_INTERFACE_DEFINED__ -#define __IMarshalEnvoy_INTERFACE_DEFINED__ - -/* interface IMarshalEnvoy */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IMarshalEnvoy; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001c8-0000-0000-C000-000000000046") - IMarshalEnvoy : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetEnvoyUnmarshalClass( - /* [in] */ DWORD dwDestContext, - /* [out] */ CLSID __RPC_FAR *pClsid) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetEnvoySizeMax( - /* [in] */ DWORD dwDestContext, - /* [out] */ DWORD __RPC_FAR *pcb) = 0; - - virtual HRESULT STDMETHODCALLTYPE MarshalEnvoy( - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ DWORD dwDestContext) = 0; - - virtual HRESULT STDMETHODCALLTYPE UnmarshalEnvoy( - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppunk) = 0; - - }; - -#else /* C style interface */ - - typedef struct IMarshalEnvoyVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IMarshalEnvoy __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IMarshalEnvoy __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetEnvoyUnmarshalClass )( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ DWORD dwDestContext, - /* [out] */ CLSID __RPC_FAR *pClsid); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetEnvoySizeMax )( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ DWORD dwDestContext, - /* [out] */ DWORD __RPC_FAR *pcb); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *MarshalEnvoy )( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ DWORD dwDestContext); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *UnmarshalEnvoy )( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppunk); - - END_INTERFACE - } IMarshalEnvoyVtbl; - - interface IMarshalEnvoy - { - CONST_VTBL struct IMarshalEnvoyVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IMarshalEnvoy_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IMarshalEnvoy_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IMarshalEnvoy_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IMarshalEnvoy_GetEnvoyUnmarshalClass(This,dwDestContext,pClsid) \ - (This)->lpVtbl -> GetEnvoyUnmarshalClass(This,dwDestContext,pClsid) - -#define IMarshalEnvoy_GetEnvoySizeMax(This,dwDestContext,pcb) \ - (This)->lpVtbl -> GetEnvoySizeMax(This,dwDestContext,pcb) - -#define IMarshalEnvoy_MarshalEnvoy(This,pStream,dwDestContext) \ - (This)->lpVtbl -> MarshalEnvoy(This,pStream,dwDestContext) - -#define IMarshalEnvoy_UnmarshalEnvoy(This,pStream,riid,ppunk) \ - (This)->lpVtbl -> UnmarshalEnvoy(This,pStream,riid,ppunk) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IMarshalEnvoy_GetEnvoyUnmarshalClass_Proxy( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ DWORD dwDestContext, - /* [out] */ CLSID __RPC_FAR *pClsid); - - -void __RPC_STUB IMarshalEnvoy_GetEnvoyUnmarshalClass_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IMarshalEnvoy_GetEnvoySizeMax_Proxy( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ DWORD dwDestContext, - /* [out] */ DWORD __RPC_FAR *pcb); - - -void __RPC_STUB IMarshalEnvoy_GetEnvoySizeMax_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IMarshalEnvoy_MarshalEnvoy_Proxy( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ DWORD dwDestContext); - - -void __RPC_STUB IMarshalEnvoy_MarshalEnvoy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IMarshalEnvoy_UnmarshalEnvoy_Proxy( - IMarshalEnvoy __RPC_FAR * This, - /* [in] */ IStream __RPC_FAR *pStream, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppunk); - - -void __RPC_STUB IMarshalEnvoy_UnmarshalEnvoy_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IMarshalEnvoy_INTERFACE_DEFINED__ */ - - -#ifndef __IWrapperInfo_INTERFACE_DEFINED__ -#define __IWrapperInfo_INTERFACE_DEFINED__ - -/* interface IWrapperInfo */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IWrapperInfo; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("5052f924-7ab8-11d3-b93f-00c04f990176") - IWrapperInfo : public IUnknown - { - public: - virtual void STDMETHODCALLTYPE SetMapping( - void __RPC_FAR *pv) = 0; - - virtual void __RPC_FAR *STDMETHODCALLTYPE GetMapping( void) = 0; - - virtual IObjContext __RPC_FAR *STDMETHODCALLTYPE GetServerObjectContext( void) = 0; - - virtual IUnknown __RPC_FAR *STDMETHODCALLTYPE GetServerObject( void) = 0; - - }; - -#else /* C style interface */ - - typedef struct IWrapperInfoVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IWrapperInfo __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IWrapperInfo __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IWrapperInfo __RPC_FAR * This); - - void ( STDMETHODCALLTYPE __RPC_FAR *SetMapping )( - IWrapperInfo __RPC_FAR * This, - void __RPC_FAR *pv); - - void __RPC_FAR *( STDMETHODCALLTYPE __RPC_FAR *GetMapping )( - IWrapperInfo __RPC_FAR * This); - - IObjContext __RPC_FAR *( STDMETHODCALLTYPE __RPC_FAR *GetServerObjectContext )( - IWrapperInfo __RPC_FAR * This); - - IUnknown __RPC_FAR *( STDMETHODCALLTYPE __RPC_FAR *GetServerObject )( - IWrapperInfo __RPC_FAR * This); - - END_INTERFACE - } IWrapperInfoVtbl; - - interface IWrapperInfo - { - CONST_VTBL struct IWrapperInfoVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IWrapperInfo_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IWrapperInfo_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IWrapperInfo_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IWrapperInfo_SetMapping(This,pv) \ - (This)->lpVtbl -> SetMapping(This,pv) - -#define IWrapperInfo_GetMapping(This) \ - (This)->lpVtbl -> GetMapping(This) - -#define IWrapperInfo_GetServerObjectContext(This) \ - (This)->lpVtbl -> GetServerObjectContext(This) - -#define IWrapperInfo_GetServerObject(This) \ - (This)->lpVtbl -> GetServerObject(This) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -void STDMETHODCALLTYPE IWrapperInfo_SetMapping_Proxy( - IWrapperInfo __RPC_FAR * This, - void __RPC_FAR *pv); - - -void __RPC_STUB IWrapperInfo_SetMapping_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -void __RPC_FAR *STDMETHODCALLTYPE IWrapperInfo_GetMapping_Proxy( - IWrapperInfo __RPC_FAR * This); - - -void __RPC_STUB IWrapperInfo_GetMapping_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -IObjContext __RPC_FAR *STDMETHODCALLTYPE IWrapperInfo_GetServerObjectContext_Proxy( - IWrapperInfo __RPC_FAR * This); - - -void __RPC_STUB IWrapperInfo_GetServerObjectContext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -IUnknown __RPC_FAR *STDMETHODCALLTYPE IWrapperInfo_GetServerObject_Proxy( - IWrapperInfo __RPC_FAR * This); - - -void __RPC_STUB IWrapperInfo_GetServerObject_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IWrapperInfo_INTERFACE_DEFINED__ */ - - -/* interface __MIDL_itf_contxt_0092 */ -/* [local] */ - - -typedef DWORD APARTMENTID; - - - -extern RPC_IF_HANDLE __MIDL_itf_contxt_0092_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_contxt_0092_v0_0_s_ifspec; - -#ifndef __IComThreadingInfo_INTERFACE_DEFINED__ -#define __IComThreadingInfo_INTERFACE_DEFINED__ - -/* interface IComThreadingInfo */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IComThreadingInfo; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001ce-0000-0000-C000-000000000046") - IComThreadingInfo : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE GetCurrentApartmentType( - /* [out] */ APTTYPE __RPC_FAR *pAptType) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadType( - /* [out] */ THDTYPE __RPC_FAR *pThreadType) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetCurrentLogicalThreadId( - /* [out] */ GUID __RPC_FAR *pguidLogicalThreadId) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetCurrentLogicalThreadId( - /* [in] */ REFGUID rguid) = 0; - - }; - -#else /* C style interface */ - - typedef struct IComThreadingInfoVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IComThreadingInfo __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IComThreadingInfo __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IComThreadingInfo __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetCurrentApartmentType )( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ APTTYPE __RPC_FAR *pAptType); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetCurrentThreadType )( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ THDTYPE __RPC_FAR *pThreadType); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetCurrentLogicalThreadId )( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ GUID __RPC_FAR *pguidLogicalThreadId); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetCurrentLogicalThreadId )( - IComThreadingInfo __RPC_FAR * This, - /* [in] */ REFGUID rguid); - - END_INTERFACE - } IComThreadingInfoVtbl; - - interface IComThreadingInfo - { - CONST_VTBL struct IComThreadingInfoVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IComThreadingInfo_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IComThreadingInfo_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IComThreadingInfo_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IComThreadingInfo_GetCurrentApartmentType(This,pAptType) \ - (This)->lpVtbl -> GetCurrentApartmentType(This,pAptType) - -#define IComThreadingInfo_GetCurrentThreadType(This,pThreadType) \ - (This)->lpVtbl -> GetCurrentThreadType(This,pThreadType) - -#define IComThreadingInfo_GetCurrentLogicalThreadId(This,pguidLogicalThreadId) \ - (This)->lpVtbl -> GetCurrentLogicalThreadId(This,pguidLogicalThreadId) - -#define IComThreadingInfo_SetCurrentLogicalThreadId(This,rguid) \ - (This)->lpVtbl -> SetCurrentLogicalThreadId(This,rguid) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IComThreadingInfo_GetCurrentApartmentType_Proxy( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ APTTYPE __RPC_FAR *pAptType); - - -void __RPC_STUB IComThreadingInfo_GetCurrentApartmentType_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IComThreadingInfo_GetCurrentThreadType_Proxy( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ THDTYPE __RPC_FAR *pThreadType); - - -void __RPC_STUB IComThreadingInfo_GetCurrentThreadType_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IComThreadingInfo_GetCurrentLogicalThreadId_Proxy( - IComThreadingInfo __RPC_FAR * This, - /* [out] */ GUID __RPC_FAR *pguidLogicalThreadId); - - -void __RPC_STUB IComThreadingInfo_GetCurrentLogicalThreadId_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IComThreadingInfo_SetCurrentLogicalThreadId_Proxy( - IComThreadingInfo __RPC_FAR * This, - /* [in] */ REFGUID rguid); - - -void __RPC_STUB IComThreadingInfo_SetCurrentLogicalThreadId_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IComThreadingInfo_INTERFACE_DEFINED__ */ - - -#ifndef __IComDispatchInfo_INTERFACE_DEFINED__ -#define __IComDispatchInfo_INTERFACE_DEFINED__ - -/* interface IComDispatchInfo */ -/* [unique][uuid][object][local] */ - - -EXTERN_C const IID IID_IComDispatchInfo; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("000001d9-0000-0000-C000-000000000046") - IComDispatchInfo : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE EnableComInits( - /* [out] */ void __RPC_FAR *__RPC_FAR *ppvCookie) = 0; - - virtual HRESULT STDMETHODCALLTYPE DisableComInits( - /* [in] */ void __RPC_FAR *pvCookie) = 0; - - }; - -#else /* C style interface */ - - typedef struct IComDispatchInfoVtbl - { - BEGIN_INTERFACE - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( - IComDispatchInfo __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( - IComDispatchInfo __RPC_FAR * This); - - ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( - IComDispatchInfo __RPC_FAR * This); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *EnableComInits )( - IComDispatchInfo __RPC_FAR * This, - /* [out] */ void __RPC_FAR *__RPC_FAR *ppvCookie); - - HRESULT ( STDMETHODCALLTYPE __RPC_FAR *DisableComInits )( - IComDispatchInfo __RPC_FAR * This, - /* [in] */ void __RPC_FAR *pvCookie); - - END_INTERFACE - } IComDispatchInfoVtbl; - - interface IComDispatchInfo - { - CONST_VTBL struct IComDispatchInfoVtbl __RPC_FAR *lpVtbl; - }; - - - -#ifdef COBJMACROS - - -#define IComDispatchInfo_QueryInterface(This,riid,ppvObject) \ - (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) - -#define IComDispatchInfo_AddRef(This) \ - (This)->lpVtbl -> AddRef(This) - -#define IComDispatchInfo_Release(This) \ - (This)->lpVtbl -> Release(This) - - -#define IComDispatchInfo_EnableComInits(This,ppvCookie) \ - (This)->lpVtbl -> EnableComInits(This,ppvCookie) - -#define IComDispatchInfo_DisableComInits(This,pvCookie) \ - (This)->lpVtbl -> DisableComInits(This,pvCookie) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -HRESULT STDMETHODCALLTYPE IComDispatchInfo_EnableComInits_Proxy( - IComDispatchInfo __RPC_FAR * This, - /* [out] */ void __RPC_FAR *__RPC_FAR *ppvCookie); - - -void __RPC_STUB IComDispatchInfo_EnableComInits_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - -HRESULT STDMETHODCALLTYPE IComDispatchInfo_DisableComInits_Proxy( - IComDispatchInfo __RPC_FAR * This, - /* [in] */ void __RPC_FAR *pvCookie); - - -void __RPC_STUB IComDispatchInfo_DisableComInits_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IComDispatchInfo_INTERFACE_DEFINED__ */ - - -/* interface __MIDL_itf_contxt_0094 */ -/* [local] */ - -typedef DWORD HActivator; - -STDAPI CoCreateObjectInContext(IUnknown *pUnk, IObjContext *pObjectCtx, REFIID riid, void **ppv); -STDAPI CoGetApartmentID(APTTYPE dAptType, HActivator* pAptID); -STDAPI CoDeactivateObject(IUnknown *pUnk, IUnknown **ppCookie); -STDAPI CoReactivateObject(IUnknown *pUnk, IUnknown *pCookie); -#define MSHLFLAGS_NO_IEC 0x8 // don't use IExternalConnextion -#define MSHLFLAGS_NO_IMARSHAL 0x10 // don't use IMarshal -#define CONTEXTFLAGS_FROZEN 0x01 // Frozen context -#define CONTEXTFLAGS_ALLOWUNAUTH 0x02 // Allow unauthenticated calls -#define CONTEXTFLAGS_ENVOYCONTEXT 0x04 // Envoy context -#define CONTEXTFLAGS_DEFAULTCONTEXT 0x08 // Default context -#define CONTEXTFLAGS_STATICCONTEXT 0x10 // Static context -#define CONTEXTFLAGS_INPROPTABLE 0x20 // Is in property table -#define CONTEXTFLAGS_INDESTRUCTOR 0x40 // Is in destructor -#define CONTEXTFLAGS_URTPROPPRESENT 0x80 // CLR property added - - -extern RPC_IF_HANDLE __MIDL_itf_contxt_0094_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_contxt_0094_v0_0_s_ifspec; - -/* Additional Prototypes for ALL interfaces */ - -/* end of Additional Prototypes */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/coreclr/inc/corhlprpriv.h b/src/coreclr/inc/corhlprpriv.h index 38faa6f6ef8be..2c8372860ba2e 100644 --- a/src/coreclr/inc/corhlprpriv.h +++ b/src/coreclr/inc/corhlprpriv.h @@ -605,7 +605,7 @@ class RidBitmap HRESULT hr = S_OK; mdToken rid = RidFromToken(token); SIZE_T index = rid / 8; - BYTE bit = (1 << (rid % 8)); + BYTE bit = (BYTE)(1 << (rid % 8)); if (index >= buffer.Size()) { @@ -623,7 +623,7 @@ class RidBitmap { mdToken rid = RidFromToken(token); SIZE_T index = rid / 8; - BYTE bit = (1 << (rid % 8)); + BYTE bit = (BYTE)(1 << (rid % 8)); return ((index < buffer.Size()) && (buffer[index] & bit)); } diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 7a673e52d7cc7..91c5734c90588 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -640,9 +640,14 @@ enum CorInfoHelpFunc CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint + CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted. + CORINFO_HELP_CLASSPROFILE32, // Update 32-bit class profile for a call site CORINFO_HELP_CLASSPROFILE64, // Update 64-bit class profile for a call site - CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted. + CORINFO_HELP_DELEGATEPROFILE32, // Update 32-bit method profile for a delegate call site + CORINFO_HELP_DELEGATEPROFILE64, // Update 64-bit method profile for a delegate call site + CORINFO_HELP_VTABLEPROFILE32, // Update 32-bit method profile for a vtable call site + CORINFO_HELP_VTABLEPROFILE64, // Update 64-bit method profile for a vtable call site CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer @@ -954,11 +959,14 @@ enum CorInfoClassId enum CorInfoInline { - INLINE_PASS = 0, // Inlining OK + INLINE_PASS = 0, // Inlining OK + INLINE_PREJIT_SUCCESS = 1, // Inline check for prejit checking usage succeeded + INLINE_CHECK_CAN_INLINE_SUCCESS = 2, // JIT detected it is permitted to try to actually inline + INLINE_CHECK_CAN_INLINE_VMFAIL = 3, // VM specified that inline must fail via the CanInline api // failures are negative - INLINE_FAIL = -1, // Inlining not OK for this case only - INLINE_NEVER = -2, // This method should never be inlined, regardless of context + INLINE_FAIL = -1, // Inlining not OK for this case only + INLINE_NEVER = -2, // This method should never be inlined, regardless of context }; enum CorInfoInlineTypeCheck @@ -2034,6 +2042,11 @@ class ICorStaticInfo CORINFO_METHOD_HANDLE calleeHnd /* IN */ ) = 0; + // Report that an inlining related process has begun. This will always be paired with + // a call to reportInliningDecision unless the jit fails. + virtual void beginInlining (CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) = 0; + // Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all // inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the // JIT. diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h index 54aaded8f9018..380db270e1cbf 100644 --- a/src/coreclr/inc/corjit.h +++ b/src/coreclr/inc/corjit.h @@ -330,7 +330,8 @@ class ICorJitInfo : public ICorDynamicInfo // Data structure for a single class probe using 32-bit count. // - // CLASS_FLAG and INTERFACE_FLAG are placed into the Other field in the schema + // CLASS_FLAG, INTERFACE_FLAG and DELEGATE_FLAG are placed into the Other field in the schema. + // If CLASS_FLAG is set the handle table consists of type handles, and otherwise method handles. // // Count is the number of times a call was made at that call site. // @@ -338,8 +339,8 @@ class ICorJitInfo : public ICorDynamicInfo // // SAMPLE_INTERVAL must be >= SIZE. SAMPLE_INTERVAL / SIZE // gives the average number of calls between table updates. - // - struct ClassProfile32 + // + struct HandleHistogram32 { enum { @@ -347,17 +348,18 @@ class ICorJitInfo : public ICorDynamicInfo SAMPLE_INTERVAL = 32, CLASS_FLAG = 0x80000000, INTERFACE_FLAG = 0x40000000, - OFFSET_MASK = 0x3FFFFFFF + DELEGATE_FLAG = 0x20000000, + OFFSET_MASK = 0x0FFFFFFF }; uint32_t Count; - CORINFO_CLASS_HANDLE ClassTable[SIZE]; + void* HandleTable[SIZE]; }; - struct ClassProfile64 + struct HandleHistogram64 { uint64_t Count; - CORINFO_CLASS_HANDLE ClassTable[ClassProfile32::SIZE]; + void* HandleTable[HandleHistogram32::SIZE]; }; enum class PgoInstrumentationKind @@ -387,7 +389,7 @@ class ICorJitInfo : public ICorDynamicInfo Done = None, // All instrumentation schemas must end with a record which is "Done" BasicBlockIntCount = (DescriptorMin * 1) | FourByte, // basic block counter using unsigned 4 byte int BasicBlockLongCount = (DescriptorMin * 1) | EightByte, // basic block counter using unsigned 8 byte int - HandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match ClassProfile32's alignment. + HandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match HandleHistogram32's alignment. HandleHistogramLongCount = (DescriptorMin * 2) | EightByte, // 8 byte counter that is part of a type histogram HandleHistogramTypes = (DescriptorMin * 3) | TypeHandle, // Histogram of type handles HandleHistogramMethods = (DescriptorMin * 3) | MethodHandle, // Histogram of method handles @@ -396,6 +398,7 @@ class ICorJitInfo : public ICorDynamicInfo EdgeIntCount = (DescriptorMin * 6) | FourByte, // edge counter using unsigned 4 byte int EdgeLongCount = (DescriptorMin * 6) | EightByte, // edge counter using unsigned 8 byte int GetLikelyClass = (DescriptorMin * 7) | TypeHandle, // Compressed get likely class data + GetLikelyMethod = (DescriptorMin * 7) | MethodHandle, // Compressed get likely method data }; struct PgoInstrumentationSchema @@ -418,7 +421,7 @@ class ICorJitInfo : public ICorDynamicInfo Sampling= 6, // PGO data derived from sampling }; -#define DEFAULT_UNKNOWN_TYPEHANDLE 1 +#define DEFAULT_UNKNOWN_HANDLE 1 #define UNKNOWN_HANDLE_MIN 1 #define UNKNOWN_HANDLE_MAX 33 diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h index d7d8378cd1f84..9a78c69a3423e 100644 --- a/src/coreclr/inc/crosscomp.h +++ b/src/coreclr/inc/crosscomp.h @@ -565,6 +565,8 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { #define DAC_CS_NATIVE_DATA_SIZE 96 #elif defined(TARGET_LINUX) && defined(TARGET_LOONGARCH64) #define DAC_CS_NATIVE_DATA_SIZE 96 +#elif defined(TARGET_LINUX) && defined(TARGET_POWERPC64) +#define DAC_CS_NATIVE_DATA_SIZE 96 #elif defined(TARGET_NETBSD) && defined(TARGET_AMD64) #define DAC_CS_NATIVE_DATA_SIZE 96 #elif defined(TARGET_NETBSD) && defined(TARGET_ARM) diff --git a/src/coreclr/inc/defaultallocator.h b/src/coreclr/inc/defaultallocator.h deleted file mode 100644 index 111fb5e7f94c0..0000000000000 --- a/src/coreclr/inc/defaultallocator.h +++ /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. - -#ifndef _DEFAULTALLOCATOR_H_ -#define _DEFAULTALLOCATOR_H_ - -// The "DefaultAllocator" class may be used by classes that wish to -// provide the flexibility of using an "IAllocator" may avoid writing -// conditionals at allocation sites about whether a non-default -// "IAllocator" has been provided: if none is, they can simply set the -// allocator to DefaultAllocator::Singleton(). -class DefaultAllocator: public IAllocator -{ - static DefaultAllocator s_singleton; - -public: - void* Alloc(size_t sz) - { - return ::operator new(sz); - } - - void* ArrayAlloc(size_t elemSize, size_t numElems) - { - ClrSafeInt safeElemSize(elemSize); - ClrSafeInt safeNumElems(numElems); - ClrSafeInt sz = safeElemSize * safeNumElems; - if (sz.IsOverflow()) - { - return NULL; - } - else - { - return ::operator new(sz.Value()); - } - } - - virtual void Free(void * p) - { - ::operator delete(p); - } - - static DefaultAllocator* Singleton() - { - return &s_singleton; - } -}; - -#endif // _DEFAULTALLOCATOR_H_ diff --git a/src/coreclr/inc/iallocator.h b/src/coreclr/inc/iallocator.h index a5b467a9905b8..f8e0978c6f10f 100644 --- a/src/coreclr/inc/iallocator.h +++ b/src/coreclr/inc/iallocator.h @@ -29,48 +29,4 @@ class IAllocator virtual void Free(void* p) = 0; }; -// This class wraps an allocator that does not allow zero-length allocations, -// producing one that does (every zero-length allocation produces a pointer to the same -// statically-allocated memory, and freeing that pointer is a no-op). -class AllowZeroAllocator: public IAllocator -{ - int m_zeroLenAllocTarg; - IAllocator* m_alloc; - -public: - AllowZeroAllocator(IAllocator* alloc) : m_alloc(alloc) {} - - void* Alloc(size_t sz) - { - if (sz == 0) - { - return (void*)(&m_zeroLenAllocTarg); - } - else - { - return m_alloc->Alloc(sz); - } - } - - void* ArrayAlloc(size_t elemSize, size_t numElems) - { - if (elemSize == 0 || numElems == 0) - { - return (void*)(&m_zeroLenAllocTarg); - } - else - { - return m_alloc->ArrayAlloc(elemSize, numElems); - } - } - - virtual void Free(void * p) - { - if (p != (void*)(&m_zeroLenAllocTarg)) - { - m_alloc->Free(p); - } - } -}; - #endif // _IALLOCATOR_DEFINED_ diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 87f3054e6269e..4864b03309694 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -44,6 +44,10 @@ CorInfoInline canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd) override; +void beginInlining( + CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) override; + void reportInliningDecision( CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index e03d9d9190c60..9a6cbc053e1ce 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 5868685e-b877-4ef5-83f0-73d601e50013 */ - 0x5868685e, - 0xb877, - 0x4ef5, - {0x83, 0xf0, 0x73, 0xd6, 0x01, 0xe5, 0x00, 0x13} +constexpr GUID JITEEVersionIdentifier = { /* f2faa5fc-a1ec-4244-aebb-5597bfd7153a */ + 0xf2faa5fc, + 0xa1ec, + 0x4244, + {0xae, 0xbb, 0x55, 0x97, 0xbf, 0xd7, 0x15, 0x3a} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index e40eb4105ee3c..a500c298978b6 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -328,9 +328,14 @@ #endif JITHELPER(CORINFO_HELP_PATCHPOINT, JIT_Patchpoint, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_CLASSPROFILE32, JIT_ClassProfile32, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_CLASSPROFILE64, JIT_ClassProfile64, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_DELEGATEPROFILE32, JIT_DelegateProfile32, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_DELEGATEPROFILE64, JIT_DelegateProfile64, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_VTABLEPROFILE32, JIT_VTableProfile32, CORINFO_HELP_SIG_4_STACK) + JITHELPER(CORINFO_HELP_VTABLEPROFILE64, JIT_VTableProfile64, CORINFO_HELP_SIG_4_STACK) #if defined(TARGET_AMD64) || defined(TARGET_ARM64) JITHELPER(CORINFO_HELP_VALIDATE_INDIRECT_CALL, JIT_ValidateIndirectCall, CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/inc/llvm/ELF.h b/src/coreclr/inc/llvm/ELF.h index 9e89b48b514a3..b38ecf9eba73a 100644 --- a/src/coreclr/inc/llvm/ELF.h +++ b/src/coreclr/inc/llvm/ELF.h @@ -829,7 +829,7 @@ struct Elf32_Sym { void setBinding(unsigned char b) { setBindingAndType(b, getType()); } void setType(unsigned char t) { setBindingAndType(getBinding(), t); } void setBindingAndType(unsigned char b, unsigned char t) { - st_info = (b << 4) + (t & 0x0f); + st_info = (unsigned char)((b << 4) + (t & 0x0f)); } }; @@ -849,7 +849,7 @@ struct Elf64_Sym { void setBinding(unsigned char b) { setBindingAndType(b, getType()); } void setType(unsigned char t) { setBindingAndType(getBinding(), t); } void setBindingAndType(unsigned char b, unsigned char t) { - st_info = (b << 4) + (t & 0x0f); + st_info = (unsigned char)((b << 4) + (t & 0x0f)); } }; diff --git a/src/coreclr/inc/pedecoder.h b/src/coreclr/inc/pedecoder.h index 7cd145f452082..2bb79e34b6b01 100644 --- a/src/coreclr/inc/pedecoder.h +++ b/src/coreclr/inc/pedecoder.h @@ -83,6 +83,8 @@ inline CHECK CheckOverflow(RVA value1, COUNT_T value2) #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_ARM64 #elif defined(TARGET_LOONGARCH64) #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_LOONGARCH64 +#elif defined(TARGET_POWERPC64) +#define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_POWERPC #elif defined(TARGET_S390X) #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_UNKNOWN #else diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 76354362d57d8..20db29298cfba 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -16,7 +16,7 @@ // Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs #define READYTORUN_MAJOR_VERSION 0x0006 -#define READYTORUN_MINOR_VERSION 0x0001 +#define READYTORUN_MINOR_VERSION 0x0002 #define MINIMUM_READYTORUN_MAJOR_VERSION 0x006 diff --git a/src/coreclr/inc/regex_base.h b/src/coreclr/inc/regex_base.h deleted file mode 100644 index fd6103f5da4b3..0000000000000 --- a/src/coreclr/inc/regex_base.h +++ /dev/null @@ -1,972 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// -// Provides basic interpreted regular expression matching. This is meant as a debugging tool, -// and if regular expressions become necessary in a non-debug scenario great care should be -// used to ensure that performance is not impaired, and a more thorough review of this could -// would also be a good thing. This file does not include any concrete instantiations but -// instead provides the basic building blocks. Some concrete instantiations can be found in -// regex_util.h. -// -// NOTE: See code:clr::regex::RegExBase (below) for description of supported regex language. -// -// NOTE: we had to forego standard options such as tr1::regex -// (http://en.wikipedia.org/wiki/Technical_Report_1#Regular_Expressions) and Microsoft's -// internal GRETA regular expressions (http://toolbox/sites/987/default.aspx) because they -// both rely heavily on the STL, which can not currently be used within the CLR. -// -// NOTE: If this becomes non-debug-only, then read the comment on WCHARItemTraits for what -// what needs fixing. -// - -// - -#ifndef _REGEX_BASE_H_ -#define _REGEX_BASE_H_ - -// Forward declare namespace so that it is not debug-only (even if currently there is nothing -// but debug-only code in the namespace). This enables a "using namespace clr;" line in a -// header file without having to worry about whether or not it's in a debug-only block. -namespace clr {} - -#ifdef _DEBUG - -#include "utilcode.h" // for string hash functions -#include "sstring.h" - -namespace clr { -namespace regex { - -// Implementation details. Code contained in any "imp" namespace should never be directly used -// by clients of RegEx. -namespace imp { - - //=================================================================================================== - // Helper for clr::regex::RegExBase. See class definition for clr::regex::RegExBase below for more - // information. - - template - class RegExBaseHelper : protected ITEM_TRAITS - { - public: - typedef typename ITEM_TRAITS::RegexIterator RegexIterator; - typedef typename ITEM_TRAITS::InputIterator InputIterator; - - typedef typename ITEM_TRAITS::MatchFlags MatchFlags; - static const MatchFlags DefaultMatchFlags = ITEM_TRAITS::DefaultMatchFlags; - - // Arguments: - // regex : marks the start of the regular expression string. - // regexEnd : marks the end of the regular expression string. - // input : marks the start of the input string against which regex will be matched. - // inputEnd : marks the end of the input string. - // groups : recipient of regular expression groups. - // - // Returns true if the regular expression was successfully matched against the input string; - // otherwise false. - - RegExBaseHelper(const RegexIterator& regex, - const RegexIterator& regexEnd, - const InputIterator& input, - const InputIterator& inputEnd, - GROUP_CONTAINER& groups, - const MatchFlags flags = DefaultMatchFlags); - - // The main entrypoint to RegExBaseHelper, Match will attempt to match the regular expression - // defined by [regex,regexEnd) against the input defined by [input,inputEnd). - bool Match() - { WRAPPER_NO_CONTRACT; return DoMatch(m_regex, m_input); } - - protected: - typedef typename ITEM_TRAITS::Item Item; - typedef typename ITEM_TRAITS::ItemType ItemType; - - // Try to match regex at any point within input, starting with the first character and moving - // along one at a time until a match is found or the end of the input is encountered, whichever - // comes first. - bool DoMatch( - const RegexIterator& regex, - InputIterator input); - - // Try to match regex starting exactly at input. - bool DoMatchHere( - const RegexIterator& regex, - const InputIterator& input); - - // The function returns true if a match is found consisting of zero or more items c followed by a - // successful match of regex on the remaining input; otherwise false is returned. This is a - // conservative match, so it starts with trying to match zero items followed by regex, - // and will then try to match one item followed by regex. - bool DoMatchStar( - const Item& c, - const RegexIterator& regex, - InputIterator input); - - // The function returns true if a match is found consisting of zero or more items c followed by a - // successful match of regex on the remaining input; otherwise false is returned. This is a - // greedy match, so it starts with trying to match as many items as it can followed by regex, - // and on failure will try again with one less items matched. - bool DoMatchStarEagerly( - const Item& c, - const RegexIterator& regex, - InputIterator input); - - // Convenience method. - Item GetItem( - const RegexIterator ®ex) - { WRAPPER_NO_CONTRACT; return ITEM_TRAITS::GetItem(regex, m_regexEnd, m_flags); } - - // Convenience method. - bool MatchItem( - const Item& c, - const InputIterator& input) - { WRAPPER_NO_CONTRACT; return ITEM_TRAITS::MatchItem(c, input, m_inputEnd, m_flags); } - - // Declared as protected to prevent direct instantiation. - RegExBaseHelper() - {} - - RegexIterator m_regex; - RegexIterator m_regexEnd; - InputIterator m_input; - InputIterator m_inputEnd; - GROUP_CONTAINER& m_groups; - MatchFlags m_flags; - }; - - //--------------------------------------------------------------------------------------------------- - // This method simply stores the end iterators for the regular expression and the input strings, as - // well as the group collection object and flags, and forwards the call to DoMatch. - - template - RegExBaseHelper::RegExBaseHelper( - const RegexIterator& regex, - const RegexIterator& regexEnd, - const InputIterator& input, - const InputIterator& inputEnd, - GROUP_CONTAINER& groups, - const MatchFlags flags) - : m_regex(regex), - m_regexEnd(regexEnd), - m_input(input), - m_inputEnd(inputEnd), - m_groups(groups), - m_flags(flags) - { WRAPPER_NO_CONTRACT; } - - //--------------------------------------------------------------------------------------------------- - // This method checks if the regular expression starts with a caret, indicating that any match must - // be anchored at the start of the input string. If such a caret exists, one match attempt is made - // on the input starting with the first character and the result is returned. If the regex does not - // start with a caret, the method attempts to match against the input string, starting at the first - // character and moving one character over for each successive attempt, until a match is found or - // the end of the input is encountered, whichever comes first. - - template - inline bool - RegExBaseHelper::DoMatch( - const RegexIterator& regex, - InputIterator input) - { - WRAPPER_NO_CONTRACT; - - if (GetItem(regex).GetType() == ITEM_TRAITS::CARET) - { // Match must occur from the beginning of the line - m_groups.OpenGroup(input, m_inputEnd); - bool res = DoMatchHere(regex+1, input); - if (!res) - m_groups.CancelGroup(); - return res; - } - else - { // Match can happen anywhere in the string - do - { // Attempt to match against each substring [x,inputEnd) for x = 0...inputEnd - - // Begin the group that contains the entire match. - m_groups.OpenGroup(input, m_inputEnd); - - if (DoMatchHere(regex, input)) - { // Success. Note that the entire match group is closed elsewhere on a - // successful match. - return true; - } - - // On failure, cancel the group so that it can be reopened on the new substring - m_groups.CancelGroup(); - } while (input++ != m_inputEnd); - } - - // No successful match found. - return false; - } - - //------------------------------------------------------------------------------------------------------- - // This is the main loop, which handles grouping constructs, repetition directives (*, *?, +, +?), and - // EOL matches ($), delegating all character matching to ITEM_TRAITS::MatchItem - // The general algorithm is: - // 1. Get the next item. - // 2. If the item is a DOLLAR type, check to see if we're at the end of the retular expression and - // the input string, and if so return success. - // 3. If the item is a grouping construct, open or close the appropriate group and continue matching. - // On failure, roll back the grouping change so that subsequent attemts will have correct state. - // 4. Check to see if the item following the current is a repetition directive, and if so take the - // appropriate action. - // 5. Otherwise defer to ITEM_TRAITS::MatchItem and if successful continue to match the remaining - // regular expression and input string; otherwise return failure. - - template - inline bool - RegExBaseHelper::DoMatchHere( - const RegexIterator& regex, - const InputIterator& input) - { - WRAPPER_NO_CONTRACT; - - if (regex == m_regexEnd) - { // Reached the end of the regular expression without ever returning false, - // implying a successful match. Close the overall match group and return. - m_groups.CloseGroup(input); - return true; - } - - Item c0 = GetItem(regex); - if (c0.GetType() == ITEM_TRAITS::DOLLAR && (c0.GetNext() == m_regexEnd)) - { // Matches EOL if a '$' is encountered at the end of the input. - m_groups.CloseGroup(input); - // Success only if we're actually at the end of the input string. - return input == m_inputEnd; - } - if (c0.GetType() == ITEM_TRAITS::PAREN_OPEN) - { // Encountered an open parenthesis ('('); open a new grouping. - m_groups.OpenGroup(input, m_inputEnd); - bool res = DoMatchHere(c0.GetNext(), input); - if (!res) - { // If a match fails, there could be further attempts (such as if - // there is an active repetition matching frame beneath us), so - // need to cancel the group we just opened so that the grouping - // structure remains consistent. - m_groups.CancelGroup(); - } - return res; - } - if (c0.GetType() == ITEM_TRAITS::PAREN_CLOSE) - { // Close the most recent open grouping. - COUNT_T i = m_groups.CloseGroup(input); - bool res = DoMatchHere(c0.GetNext(), input); - if (!res) - { // For the same reasons as the need to cancel an opened group - // explained above, we need to reopen the closed group if a - // match fails. - m_groups.ReopenGroup(i, m_inputEnd); - } - return res; - } - - if (c0.GetNext() != m_regexEnd) - { // If there is another item in the regex string following the current one, get - // it to see if it is a repetition matching directive. - Item c1 = GetItem(c0.GetNext()); - if (c1.GetType() == ITEM_TRAITS::STAR) - { // '*' matching directive encountered - if (c1.GetNext() != m_regexEnd) - { - Item c2 = GetItem(c1.GetNext()); - if (c2.GetType() == ITEM_TRAITS::QUESTION_MARK) - { // conservative matching semantics requested - return DoMatchStar(c0, c2.GetNext(), input); - } - } - // Eager matching - return DoMatchStarEagerly(c0, c1.GetNext(), input); - } - if (c1.GetType() == ITEM_TRAITS::PLUS) - { // '+' matching directive encountered. - if (c1.GetNext() != m_regexEnd) - { - Item c2 = GetItem(c1.GetNext()); - if (c2.GetType() == ITEM_TRAITS::QUESTION_MARK) - { // conservative matching semantics requested - return MatchItem(c0, input) && DoMatchStar(c0, c2.GetNext(), input+1); - } - } - // Eager matching - return MatchItem(c0, input) && DoMatchStarEagerly(c0, c1.GetNext(), input+1); - } - if (c1.GetType() == ITEM_TRAITS::QUESTION_MARK) - { // '?' matching directive encountered - return (MatchItem(c0, input) && DoMatchHere(c1.GetNext(), input+1)) || DoMatchHere(c1.GetNext(), input); - } - } - - // No special matching semantics encountered, delegate the matching to ITEM_TRAITS::MatchItem - return MatchItem(c0, input) && DoMatchHere(c0.GetNext(), input+1); - } - - //------------------------------------------------------------------------------------------------------- - // Conservative '*' repetition matching. This attempts to match zero items c followed by a match of - // regex. If this fails, attempt to match one item c followed by a match of regex. Repeat until item c - // does not match or a successful match is found. - - template - inline bool - RegExBaseHelper::DoMatchStar( - const Item& c, - const RegexIterator& regex, - InputIterator input) - { - WRAPPER_NO_CONTRACT; - CONSISTENCY_CHECK(input != m_inputEnd); - - do { - if (DoMatchHere(regex, input)) - { // A successful match is found! - return true; - } - // No successful match, so try to match one more item and then attempt to match regex on the - // remaining input. - } while (input != m_inputEnd && MatchItem(c, input++)); - return false; - } - - //------------------------------------------------------------------------------------------------------- - // Similar to DoMatchStar above, except this algorithm matches as many items c as possible first followed - // by regex on the remaining input, and on failure tries again with a match against one less item c - // followed by regex on the remaining input, and repeats until there are no items c remaining to match - // and the zero item match followed by a match of regex on the entire remaining input fails. If any of - // the match attempts succeed, return success. - - template - inline bool - RegExBaseHelper::DoMatchStarEagerly( - const Item& c, - const RegexIterator& regex, - InputIterator input) - { - WRAPPER_NO_CONTRACT; - - // Make sure we keep a hold of how far back we can unwind. - InputIterator inputOrig = input; - - // First, determine the maximum number of matches against item c. - while (input != m_inputEnd && MatchItem(c, input)) - { - ++input; - } - - do - { // Work backwards from the maximum number of matches of item c until a match is found - // or until we have backed right up to the starting value of input (saved in inputOrig), - // at which time we admit failure. - if (DoMatchHere(regex, input)) - return true; - } while (inputOrig != input--); - return false; - } - -} // namespace imp - -//======================================================================================================= -// Represents a matched group using iterators to denote the string contained by [Begin(),End()). - -template -class Group -{ -public: - typedef INPUT_ITERATOR InputIterator; - - // - // Functions for accessing group properties - // - - // Returns the iterator indicating the start of the group - const InputIterator& Begin() const - { LIMITED_METHOD_CONTRACT; return m_begin; } - - // Returns the iterator indicating the first non-member of the group - const InputIterator& End() const - { LIMITED_METHOD_CONTRACT; return m_end; } - - // It is possible that m_end - m_begin could be greater than the maximum of COUNT_T. m_end and - // m_begin are the end and start of a string, so is entirely unlikely to overflow a COUNT_T. - // Conbined with the fact that this is debug-only code, opting not to replace all COUNT_T - // uses with SIZE_T. - COUNT_T Length() const - { WRAPPER_NO_CONTRACT; return static_cast(m_end - m_begin); } - - // - // Functions used by RegExBaseHelper to create grouping constructs. - // - - Group() - : m_isClosed(false), m_begin(), m_end() - { WRAPPER_NO_CONTRACT; } - - Group(const InputIterator& start, const InputIterator& end, bool isClosed = false) - : m_isClosed(isClosed), m_begin(start), m_end(end) - { WRAPPER_NO_CONTRACT; } - - void SetBegin(const InputIterator& start) - { WRAPPER_NO_CONTRACT; m_begin = start; } - - void SetEnd(const InputIterator& end) - { WRAPPER_NO_CONTRACT; m_end = end; } - - bool IsClosed() const - { LIMITED_METHOD_CONTRACT; return m_isClosed; } - - void SetIsClosed(bool isClosed) - { WRAPPER_NO_CONTRACT; m_isClosed = isClosed; } - -protected: - bool m_isClosed; - InputIterator m_begin; - InputIterator m_end; -}; - -//======================================================================================================= -// Represents a generic container of groups, defaulting to using Group as its element -// type. This container satisfies the method requrements of RegExBase. When a match is successful, the -// match groups may be accessed using the index operator or the iterators definin the matched groups -// [Begin(), End()). - -template > -class GroupContainer -{ -public: - typedef typename SArray::Iterator Iterator; - - // - // Functions for enumerating groups - // - - GROUP_TYPE & operator[](COUNT_T idx) - { - WRAPPER_NO_CONTRACT; - CONSISTENCY_CHECK(((COUNT_T)(COUNT_T)idx) == idx); - return m_array[idx]; - } - - // Returns an iterator to the first matched group (which is always the string for the - // entire successfully matched string. Specific groups start at Begin()+1 and continue - // to End()-1. - Iterator Begin() - { WRAPPER_NO_CONTRACT; return m_array.Begin(); } - - // Returns the first invalid iterator value. - Iterator End() - { WRAPPER_NO_CONTRACT; return m_array.End(); } - - // - COUNT_T Count() const - { WRAPPER_NO_CONTRACT; return m_array.GetCount(); } - - // - // Functions used by RegExBaseHelper to create grouping constructs. - // - - // Note: OpenGroup takes an end iterator so that the group will have a valid (if possibly - // incorrect) endpoint in the case that the regular expression has unbalanced grouping - // parentheses. - void OpenGroup(const INPUT_ITERATOR& start, const INPUT_ITERATOR& end) - { WRAPPER_NO_CONTRACT; m_array.Append(GROUP_TYPE(start, end, false)); } - - COUNT_T CloseGroup(const INPUT_ITERATOR& end); - - void ReopenGroup(COUNT_T i, const INPUT_ITERATOR& end); - - void CancelGroup() - { WRAPPER_NO_CONTRACT; m_array.Delete(m_array.End() - 1); } - -private: - SArray m_array; -}; - -//------------------------------------------------------------------------------------------------------- -// Works backwards from the most recently created group looking for an open group to close. Returns -// the index of the group that was closed, which is used in the event that a group needs to be -// reopened. - -template -COUNT_T -GroupContainer::CloseGroup( - const INPUT_ITERATOR& end) -{ - WRAPPER_NO_CONTRACT; - - for (COUNT_T i = (COUNT_T)Count(); i > 0; --i) - { - if (!m_array[i-1].IsClosed()) - { - m_array[i-1].SetEnd(end); - m_array[i-1].SetIsClosed(true); - return i-1; - } - } - - _ASSERTE(!"Unmatched grouping constructs!"); - return 0; -} - -//------------------------------------------------------------------------------------------------------- -// Reopen a group at the given index, using 'end' to overwrite the current end. - -template -void -GroupContainer::ReopenGroup( - COUNT_T i, - const INPUT_ITERATOR& end) -{ - WRAPPER_NO_CONTRACT; - CONSISTENCY_CHECK(i > 0 && i < Count()); - - if (i > 0 && i < Count()) - { - m_array[i].SetEnd(end); - m_array[i].SetIsClosed(false); - } -} - -//======================================================================================================= -// Empty group container that satisfies the method requirements of RegExBase but has empty bodies. This -// allows for non-allocating matches when grouping is not required. - -template -class NullGroupContainer -{ -public: - void OpenGroup(INPUT_ITERATOR, INPUT_ITERATOR) {} - COUNT_T CloseGroup(INPUT_ITERATOR) { return 0; } - void ReopenGroup(COUNT_T, INPUT_ITERATOR) {} - void CancelGroup() {} -}; - -//======================================================================================================= -// This mini-implementation of regular expression matching supports the -// following constructs: -// ^ matches the beginning of the input string -// $ matches the end of the input string -// * matches zero or more occurrences of the previous item eagerly -// *? matches zero or more occurrences of the previous item conservatively -// + matches 1 or more occurrences of the previous item eagerly -// +? matches 1 or more occurrences of the previous item conservatively -// ? matches 0 or 1 occurrences of the previous item -// ( starts a grouping -// ) ends a grouping -// -// IMPORTANT: These are just anchoring and grouping constructs. See the definition for ItemTraitsBase -// below for information on the default character classes that are supported. (The intent of -// this separation is to allow customization of the character classes where required.) - -// ITEM_TRAITS provides traits for individual tokens in a regular expression, as well as a mechanism for -// matching said individual components with the target string. RegexBase derives from ITEM_TRAITS in a -// protected fashion, and is responsible for providing the following: -// 1. "RegexIterator" typedef -// Used as an iterator into the regular expression, and used as arguments to indicate the start -// and the end of the regular expression string. -// 2. "InputIterator" typedef -// Used as an iterator into the input string, and used as arguments to indicate the start -// and the end of the input string. -// (NOTE: RegexIterator and InputIterator are often typedef'ed to be the same thing.) -// 3. "Item" typedef. -// This will be used with methods GetItem and MatchItem (see below). Item must -// define the following methods: -// ItemType GetType() : returns the type of the item. See below for explanation of ItemType -// const RegexIterator& GetNext() : iterator pointing to the start of the next item. -// 4. "MatchFlags" typedef, and "static const DefaultMatchFlags" value. -// Provided for calls to "Match" and "Matches", and passed on to calls "GetItem" and "MatchItem". -// 5. enum ItemType -// Defines the following minimum values: -// DOT -// CARET -// DOLLAR -// STAR -// QUESTION_MARK -// PLUS -// PAREN_OPEN -// PAREN_CLOSE -// ItemType may include more values, and may even choose to ignore the above enum types, all of -// which must be recognized by GetItem and MatchItem (see below). -// 6. static Item GetItem(const RegexIterator& regex, -// const RegexIterator& regexEnd, -// const MatchFlags& flags) -// This method takes a regular expression iterator and returns the next regular expression -// element (Item) pointed to by the iterator. -// 7. static bool MatchItem(const Item& c, -// const InputIterator& input, -// const InputIterator& inputEnd, -// const MatchFlags &flags) - -// GROUP_CONTAINER provides functionality for keeping track of regular expression groups. This is a generic -// argument to Match, and the type of the object must support the following methods: -// 1. void OpenGroup(const InputIterator& start, const InputIterator& end); -// Called when a PAREN_OPEN item is encountered. -// 2. COUNT_T CloseGroup(const InputIterator& end); -// Called when a PAREN_CLOSE item is encountered. Returns the index of the group that was closed. -// 3. void ReopenGroup(COUNT_T i, const InputIterator& end); -// Called when a match following a call to CloseGroup fails, essentially requesting a rollback -// of the call to CloseGroup. -// 4. void CancelGroup(); -// Called when a match following a call to OpenGroup fails, essentially requesting a rollback -// of the call to OpenGroup. - -template -class RegExBase : public ITEM_TRAITS -{ -public: - typedef typename ITEM_TRAITS::RegexIterator RegexIterator; - typedef typename ITEM_TRAITS::InputIterator InputIterator; - - // This is a convenience typedef that allows a caller to easily declare a grouping container - // to be passed to a call to Match. An example would be (see regex_util.h for a definition of - // SStringRegEx): - // - // SString input(SL"Simmons"); - // SStringRegEx::GroupingContainer container; - // if (SStringRegEx::Match(SL"(Sim+on)", input, container)) { - // printf("%S", container[1].GetSString(input).GetUnicode()); - // } - // - typedef GroupContainer > GroupingContainer; - - // Pulls down the typedef for MatchFlags and initialized a static representing the default flags. - typedef typename ITEM_TRAITS::MatchFlags MatchFlags; - static const MatchFlags DefaultMatchFlags = ITEM_TRAITS::DefaultMatchFlags; - - template - static bool Match(RegexIterator regex, - RegexIterator regexEnd, - InputIterator input, - InputIterator inputEnd, - GROUP_CONTAINER& groups, - MatchFlags flags = DefaultMatchFlags) - { - imp::RegExBaseHelper - re(regex, regexEnd, input, inputEnd, groups, flags); - return re.Match(); - } - - static bool Matches(RegexIterator regex, - RegexIterator regexEnd, - InputIterator input, - InputIterator inputEnd, - MatchFlags flags = DefaultMatchFlags) - { - NullGroupContainer ngc; - return Match(regex, regexEnd, input, inputEnd, ngc, flags); - } -}; - -//======================================================================================================= -// In addition to requirements specified on RegExBase, StandardItemTraits provides the following -// additinal regular expression item types. -// c matches any literal character c -// . matches any single character -// \d any literal digit character -// \w any alpha character -// \s any whitespace character -// -// Child types of ItemTraitsBase must implement GetItem and MatchItem (see below for full -// signature requirements). Current child type implementations permit a backslash ('\') to escape -// special characters ('.', '$', '*', etc.) and allow them to be interpreted as literal characters. -// -// This type describes a particular behaviour, but must be subtyped for the particular target character -// needed, and GetItem and MatchItem must be implemented. -// - -template -class ItemTraitsBase -{ -public: - typedef ITERATOR_TYPE RegexIterator; - typedef ITERATOR_TYPE InputIterator; - - enum MatchFlags - { - MF_NONE = 0x00, - MF_CASE_INSENSITIVE = 0x01 // Match character literals as case insensitive. - }; - - static const MatchFlags DefaultMatchFlags = MF_NONE; - -protected: - ItemTraitsBase() - {} - - enum ItemType - { - // REQUIRED, as described in RegExBase - CARET, - DOLLAR, - STAR, - QUESTION_MARK, - PLUS, - PAREN_OPEN, - PAREN_CLOSE, - // ADDITIONAL - DOT, // any literal character - DIGIT, // any digit - ALPHA, // any alpha character, upper or lower case - WHITESPACE, // any whitespace character - NON_WHITESPACE, // any non-whitespace character - CHARACTER, // a specific literal character - }; - - class Item - { - public: - Item(ItemType type, CHAR_TYPE val, const RegexIterator& next) - : m_type(type), m_val(val), m_next(next) - { WRAPPER_NO_CONTRACT; } - - Item(ItemType type, const RegexIterator& next) - : m_type(type), m_val(0), m_next(next) - { WRAPPER_NO_CONTRACT; } - - ItemType GetType() const - { LIMITED_METHOD_CONTRACT; return m_type; } - - const RegexIterator& GetNext() const - { LIMITED_METHOD_CONTRACT; return m_next; } - - CHAR_TYPE GetValue() const - { LIMITED_METHOD_CONTRACT; return m_val; } - - protected: - ItemType m_type; - CHAR_TYPE m_val; - RegexIterator m_next; - }; - - // All deriving types must add the following methods: - // static Item GetItem(const RegexIterator& regex, const RegexIterator& regexEnd); - // static bool MatchItem(const Item& c, const InputIterator& input, const InputIterator& inputEnd); -}; - -//======================================================================================================= -// Implements ItemTraitsBase, provides matching for UNICODE characters. -// -// !!!IMPORTANT!!! -// This is not a complete unicode implementation - only the equivalent of ASCII alpha characters are -// consider to be part of the alpha set, and this is also the only set on which case insensitive -// operations will correctly work. If RegEx is moved out of DEBUG ONLY, then this will have to be fixed -// to properly address these issues. -// !!!IMPORTANT!!! - -template -class WCHARItemTraits : public ItemTraitsBase -{ -public: - typedef ItemTraitsBase PARENT_TYPE; - typedef typename PARENT_TYPE::RegexIterator RegexIterator; - typedef typename PARENT_TYPE::InputIterator InputIterator; - typedef typename PARENT_TYPE::Item Item; - typedef typename PARENT_TYPE::MatchFlags MatchFlags; - - static Item GetItem(const RegexIterator& regex, const RegexIterator& regexEnd, MatchFlags flags); - static bool MatchItem(const Item& c, const InputIterator& input, const InputIterator& inputEnd, MatchFlags flags); - -protected: - WCHARItemTraits() - {} - -private: - static inline bool IS_UPPER_A_TO_Z(WCHAR x) - { WRAPPER_NO_CONTRACT; return (((x) >= W('A')) && ((x) <= W('Z'))); } - - static inline bool IS_LOWER_A_TO_Z(WCHAR x) - { WRAPPER_NO_CONTRACT; return (((x) >= W('a')) && ((x) <= W('z'))); } - - static inline WCHAR UPCASE(WCHAR x) - { WRAPPER_NO_CONTRACT; return (IS_LOWER_A_TO_Z(x) ? ((x) - W('a') + W('A')) : (x)); } - - static inline WCHAR DOWNCASE(WCHAR x) - { WRAPPER_NO_CONTRACT; return (IS_UPPER_A_TO_Z(x) ? ((x) - W('A') + W('a')) : (x)); } - - static bool MatchCharacter(WCHAR c1, WCHAR c2, MatchFlags flags) - { WRAPPER_NO_CONTRACT; return (flags & PARENT_TYPE::MF_CASE_INSENSITIVE) ? (DOWNCASE(c1) == DOWNCASE(c2)) : (c1 == c2); } -}; - -//------------------------------------------------------------------------------------------------------- -// Reads the next item from regex, recognizing special characters outlined in ItemTraitsBase. - -template -typename WCHARItemTraits::Item -WCHARItemTraits::GetItem( - const RegexIterator& regex, - const RegexIterator& regexEnd, - MatchFlags flags) -{ - WRAPPER_NO_CONTRACT; - - if (*regex == W('\\')) - { - const RegexIterator regexNext = regex+1; - if (regexNext == regexEnd) - return Item(PARENT_TYPE::CHARACTER, W('\\'), regexNext); - if (*regexNext == W('d')) - return Item(PARENT_TYPE::DIGIT, regexNext+1); - if (*regexNext == W('w')) - return Item(PARENT_TYPE::ALPHA, regexNext+1); - if (*regexNext == W('s')) - return Item(PARENT_TYPE::WHITESPACE, regexNext+1); - if (*regexNext == W('S')) - return Item(PARENT_TYPE::NON_WHITESPACE, regexNext+1); - return Item(PARENT_TYPE::CHARACTER, *regexNext, regexNext+1); - } - else if (*regex == W('.')) - return Item(PARENT_TYPE::DOT, W('.'), regex+1); - else if (*regex == W('^')) - return Item(PARENT_TYPE::CARET, W('^'), regex+1); - else if (*regex == W('$')) - return Item(PARENT_TYPE::DOLLAR, W('$'), regex+1); - else if (*regex == W('*')) - return Item(PARENT_TYPE::STAR, W('*'), regex+1); - else if (*regex == W('?')) - return Item(PARENT_TYPE::QUESTION_MARK, W('?'), regex+1); - else if (*regex == W('+')) - return Item(PARENT_TYPE::PLUS, W('+'), regex+1); - else if (*regex == W('(')) - return Item(PARENT_TYPE::PAREN_OPEN, W('('), regex+1); - else if (*regex == W(')')) - return Item(PARENT_TYPE::PAREN_CLOSE, W(')'), regex+1); - else - return Item(PARENT_TYPE::CHARACTER, *regex, regex + 1); -} - -//------------------------------------------------------------------------------------------------------- -// Returns true if the next character point to by input matches the character class described by c. - -template -bool -WCHARItemTraits::MatchItem( - const Item& c, - const InputIterator& input, - const InputIterator& inputEnd, - MatchFlags flags) -{ - WRAPPER_NO_CONTRACT; - - if (c.GetType() == PARENT_TYPE::DIGIT) - return *input >= W('0') && *input <= W('9'); - else if (c.GetType() == PARENT_TYPE::ALPHA) - return (*input >= W('a') && *input <= W('z')) || (*input >= W('A') && *input <= W('Z')); - else if (c.GetType() == PARENT_TYPE::WHITESPACE) - return *input == W(' ') || *input == W('\t'); - else if (c.GetType() == PARENT_TYPE::NON_WHITESPACE) - return !(*input == W(' ') || *input == W('\t')); - else - return c.GetType() == PARENT_TYPE::DOT || MatchCharacter(c.GetValue(), *input, flags); -} - -//======================================================================================================= -// Implements ItemTraitsBase, provides matching for ASCII (*not* UTF8) characters. - -template -class CHARItemTraits : public ItemTraitsBase -{ -public: - typedef ItemTraitsBase PARENT_TYPE; - typedef typename PARENT_TYPE::RegexIterator RegexIterator; - typedef typename PARENT_TYPE::InputIterator InputIterator; - typedef typename PARENT_TYPE::Item Item; - typedef typename PARENT_TYPE::MatchFlags MatchFlags; - - static Item GetItem(const RegexIterator& regex, const RegexIterator& regexEnd, MatchFlags flags); - static bool MatchItem(const Item& c, const InputIterator& input, const InputIterator& inputEnd, MatchFlags flags); - -protected: - CHARItemTraits() - {} - -private: - static inline bool IS_UPPER_A_TO_Z(CHAR x) - { WRAPPER_NO_CONTRACT; return (((x) >= 'A') && ((x) <= 'Z')); } - - static inline bool IS_LOWER_A_TO_Z(CHAR x) - { WRAPPER_NO_CONTRACT; return (((x) >= 'a') && ((x) <= 'z')); } - - static inline CHAR UPCASE(CHAR x) - { WRAPPER_NO_CONTRACT; return (IS_LOWER_A_TO_Z(x) ? ((x) - 'a' + 'A') : (x)); } - - static inline CHAR DOWNCASE(CHAR x) - { WRAPPER_NO_CONTRACT; return (IS_UPPER_A_TO_Z(x) ? ((x) - 'A' + 'a') : (x)); } - - static bool MatchCharacter(CHAR c1, CHAR c2, MatchFlags flags) - { WRAPPER_NO_CONTRACT; return (flags & PARENT_TYPE::MF_CASE_INSENSITIVE) ? (DOWNCASE(c1) == DOWNCASE(c2)) : (c1 == c2); } -}; - -//------------------------------------------------------------------------------------------------------- -// Reads the next item from regex, recognizing special characters outlined in ItemTraitsBase. - -template -typename CHARItemTraits::Item -CHARItemTraits::GetItem( - const RegexIterator& regex, - const RegexIterator& regexEnd, - MatchFlags flags) -{ - WRAPPER_NO_CONTRACT; - - if (*regex == '\\') - { - const RegexIterator regexNext = regex+1; - if (regexNext == regexEnd) - return Item(PARENT_TYPE::CHARACTER, W('\\'), regexNext); - if (*regexNext == 'd') - return Item(PARENT_TYPE::DIGIT, regexNext+1); - if (*regexNext == 'w') - return Item(PARENT_TYPE::ALPHA, regexNext+1); - if (*regexNext == 's') - return Item(PARENT_TYPE::WHITESPACE, regexNext+1); - return Item(PARENT_TYPE::CHARACTER, *regexNext, regexNext+1); - } - else if (*regex == '.') - return Item(PARENT_TYPE::DOT, '.', regex+1); - else if (*regex == '^') - return Item(PARENT_TYPE::CARET, '^', regex+1); - else if (*regex == '$') - return Item(PARENT_TYPE::DOLLAR, '$', regex+1); - else if (*regex == '*') - return Item(PARENT_TYPE::STAR, '*', regex+1); - else if (*regex == '?') - return Item(PARENT_TYPE::QUESTION_MARK, '?', regex+1); - else if (*regex == '+') - return Item(PARENT_TYPE::PLUS, '+', regex+1); - else if (*regex == '(') - return Item(PARENT_TYPE::PAREN_OPEN, '(', regex+1); - else if (*regex == ')') - return Item(PARENT_TYPE::PAREN_CLOSE, ')', regex+1); - else - return Item(PARENT_TYPE::CHARACTER, *regex, regex + 1); -} - -//------------------------------------------------------------------------------------------------------- -// Returns true if the next character point to by input matches the character class described by c. - -template -bool -CHARItemTraits::MatchItem( - const Item& c, - const InputIterator& input, - const InputIterator& inputEnd, - MatchFlags flags) -{ - WRAPPER_NO_CONTRACT; - - if (c.GetType() == PARENT_TYPE::DIGIT) - return *input >= W('0') && *input <= W('9'); - else if (c.GetType() == PARENT_TYPE::ALPHA) - return (*input >= W('a') && *input <= W('z')) || (*input >= W('A') && *input <= W('Z')); - else if (c.GetType() == PARENT_TYPE::WHITESPACE) - return *input == W(' ') || *input == W('\t'); - else - return c.GetType() == PARENT_TYPE::DOT || MatchCharacter(c.GetValue(), *input, flags); -} - -} /* namespace regex */ -} /* namespace clr */ - -#endif // _DEBUG - -#endif // _REGEX_BASE_H_ diff --git a/src/coreclr/inc/regex_util.h b/src/coreclr/inc/regex_util.h deleted file mode 100644 index d96c7423198b2..0000000000000 --- a/src/coreclr/inc/regex_util.h +++ /dev/null @@ -1,208 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// See regex_base.h for more information. -// -// This header creates some concrete instantiations of RegExBase for commonly used scenarios. In -// particular, basic regular expression matching base on the regular expression language described in -// clr::regex::ItemTraitsBase (found in regex_base.h) is instantiated for use with SString, ASCII and -// UNICODE strings (clr::regex::SStringRegex, clr::regex::WSTRRegEx, and clr::regex::STRRegEx -// respectively). Each type definition includes an example of its use. -// - -// - -#ifndef _REGEX_UTIL_H_ -#define _REGEX_UTIL_H_ - -#ifndef MODE_ANY -#define MODE_ANY -#endif - -#include "regex_base.h" - -#ifdef _DEBUG - -namespace clr -{ -namespace regex -{ - -//======================================================================================================= -// Derives from Group to provide two additional convenience methods (GetSString variants). - -class SStringGroup : public Group -{ -public: - SStringGroup() - : Group() - { WRAPPER_NO_CONTRACT; } - - SStringGroup(const InputIterator& _start, const InputIterator& _end, bool _isClosed = false) - : Group(_start, _end, _isClosed) - { WRAPPER_NO_CONTRACT; } - - // Since SStrings constructed from ranges require the original source string, this is a required - // input argument. Returns the input substring that matches the corresponding grouping. - SString GetSString(const SString& src) - { WRAPPER_NO_CONTRACT; return SString(src, Begin(), End()); } - - // Since SStrings constructed from ranges require the original source string, this is a required - // input argument. This version takes a target SString as a buffer, and also returns this buffer - // as a reference. Returns the input substring that matches the corresponding grouping. - SString& GetSString(const SString& src, SString& tgt) - { WRAPPER_NO_CONTRACT; tgt.Set(src, Begin(), End()); return tgt; } -}; - -//======================================================================================================= -typedef WCHARItemTraits SStringItemTraits; - -//======================================================================================================= -// Regular expression matching with SStrings. -// -// Here is an example of how to use SStringRegEx with grouping enabled. -// -// using namespace clr::regex; -// SString input(SL"Simmons"); // usually this is derived from some variable source -// SStringRegEx::GroupingContainer container; -// if (SStringRegEx::Match(SL"(Sim+on)", input, container)) { -// printf("%S", container[1].GetSString(input).GetUnicode()); -// } -// -// This sample should result in "Simmon" being printed. - - -class SStringRegEx : public RegExBase -{ - typedef RegExBase PARENT_TYPE; - -public: - using PARENT_TYPE::Match; - using PARENT_TYPE::Matches; - - typedef PARENT_TYPE::InputIterator InputIterator; - - typedef GroupContainer GroupingContainer; - - static bool Match( - const SString& regex, - const SString& input, - GroupingContainer& groups, - MatchFlags flags = DefaultMatchFlags) - { - WRAPPER_NO_CONTRACT; - return Match(regex.Begin(), regex.End(), input.Begin(), input.End(), groups, flags); - } - - static bool Matches( - const SString& regex, - const SString& input, - MatchFlags flags = DefaultMatchFlags) - { - WRAPPER_NO_CONTRACT; - return Matches(regex.Begin(), regex.End(), input.Begin(), input.End(), flags); - } - -}; - -//======================================================================================================= -// Regular expression matching with UNICODE strings. -// -// Here is an example of how to use WSTRRegEx to match against a null-terminated string without grouping. -// -// using namespace clr::regex; -// LPCWSTR input = L"Simmons"; -// if (WSTRRegEx::Matches(L"Sim+on", input)) -// printf("Match succeeded"); -// else -// printf("Match failed"); -// -// This sample should result in "Match succeeded" being printed. - -class WSTRRegEx : public RegExBase > -{ - typedef RegExBase > PARENT_TYPE; - -public: - using PARENT_TYPE::Match; - using PARENT_TYPE::Matches; - - static bool Match( - LPCWSTR regex, - LPCWSTR input, - GroupingContainer& groups, - MatchFlags flags = DefaultMatchFlags) - { - WRAPPER_NO_CONTRACT; - return Match(regex, regex + wcslen(regex), input, input + wcslen(input), groups, flags); - } - - static bool Matches( - LPCWSTR regex, - LPCWSTR input, - MatchFlags flags = DefaultMatchFlags) - { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } CONTRACTL_END; - - return Matches(regex, regex + wcslen(regex), input, input + wcslen(input), flags); - } -}; - -//======================================================================================================= -// Regular expression matching with ASCII strings. -// -// Here is an example of how to use STRRegEx to match against a substring based on begin and end range -// pointers, with grouping disabled and case insensitivity enabled. -// -// using namespace clr::regex; -// LPCSTR input = "123Simmons456"; -// if (STRRegEx::Matches("Sim+on", input+3, input+10, STRRegEx::MF_CASE_INSENSITIVE)) -// printf("Match succeeded"); -// else -// printf("Match failed"); -// -// This sample should result in "Match succeeded" being printed. - -class STRRegEx : public RegExBase > -{ - typedef RegExBase > PARENT_TYPE; - -public: - using PARENT_TYPE::Match; - using PARENT_TYPE::Matches; - - static bool Match( - LPCSTR regex, - LPCSTR input, - GroupingContainer& groups, - MatchFlags flags = DefaultMatchFlags) - { - WRAPPER_NO_CONTRACT; - return Match(regex, regex + strlen(regex), input, input + strlen(input), groups, flags); - } - - static bool Matches( - LPCSTR regex, - LPCSTR input, - MatchFlags flags = DefaultMatchFlags) - { - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } CONTRACTL_END; - - return Matches(regex, regex + strlen(regex), input, input + strlen(input), flags); - } -}; - -} // namespace regex -} // namespace clr - -#endif // _DEBUG - -#endif // _REGEX_UTIL_H_ diff --git a/src/coreclr/inc/sstring.h b/src/coreclr/inc/sstring.h index 5f5eeb1078e00..3145d1b1e30de 100644 --- a/src/coreclr/inc/sstring.h +++ b/src/coreclr/inc/sstring.h @@ -105,16 +105,11 @@ class EMPTY_BASES_DECL SString : private SBuffer protected: class Index; - class UIndex; friend class Index; - friend class UIndex; public: - // UIterator is character-level assignable. - class UIterator; - // CIterators/Iterator'string must be modified by SString APIs. class CIterator; class Iterator; @@ -173,6 +168,7 @@ class EMPTY_BASES_DECL SString : private SBuffer void SetASCII(const ASCII *string); void SetUTF8(const UTF8 *string); void SetANSI(const ANSI *string); + void SetAndConvertToUTF8(const WCHAR* string); // Set this string to a copy of the first count chars of the given string void Set(const WCHAR *string, COUNT_T count); @@ -325,53 +321,6 @@ class EMPTY_BASES_DECL SString : private SBuffer // CIterator and Iterator are cheap to create, but allow only read-only // access to the string. // - // UIterator forces a unicode conversion, but allows - // assignment to individual string characters. They are also a bit more - // efficient once created. - - // ------------------------------------------------------------------ - // UIterator: - // ------------------------------------------------------------------ - - protected: - - class EMPTY_BASES_DECL UIndex : public SBuffer::Index - { - friend class SString; - friend class Indexer; - - protected: - - UIndex(); - UIndex(SString *string, SCOUNT_T index); - WCHAR &GetAt(SCOUNT_T delta) const; - void Skip(SCOUNT_T delta); - SCOUNT_T Subtract(const UIndex &i) const; - CHECK DoCheck(SCOUNT_T delta) const; - - WCHAR *GetUnicode() const; - }; - - public: - - class EMPTY_BASES_DECL UIterator : public UIndex, public Indexer - { - friend class SString; - - public: - UIterator() - { - } - - UIterator(SString *string, int index) - : UIndex(string, index) - { - } - }; - - UIterator BeginUnicode(); - UIterator EndUnicode(); - // For CIterator & Iterator, we try our best to iterate the string without // modifying it. (Currently, we do require an ASCII or Unicode string // for simple WCHAR retrival, but you could imagine being more flexible @@ -544,17 +493,15 @@ class EMPTY_BASES_DECL SString : private SBuffer // SString *s = ...; // { // StackScratchBuffer buffer; - // const UTF8 *utf8 = s->GetUTF8(buffer); - // CallFoo(utf8); + // const ANSI *ansi = s->GetANSI(buffer); + // CallFoo(ansi); // } // // No more pointers to returned buffer allowed. - - const UTF8 *GetUTF8(AbstractScratchBuffer &scratch) const; - const UTF8 *GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const; const ANSI *GetANSI(AbstractScratchBuffer &scratch) const; - // Used when the representation is known, throws if the representation doesn't match - const UTF8 *GetUTF8NoConvert() const; + // You can always get a UTF8 string. This will force a conversion + // if necessary. + const UTF8 *GetUTF8() const; // Converts/copies into the given output string void ConvertToUnicode(SString &dest) const; @@ -779,6 +726,7 @@ class EMPTY_BASES_DECL SString : private SBuffer void ConvertASCIIToUnicode(SString &dest) const; void ConvertToUnicode() const; void ConvertToUnicode(const CIterator &i) const; + void ConvertToUTF8() const; const SString &GetCompatibleString(const SString &s, SString &scratch) const; const SString &GetCompatibleString(const SString &s, SString &scratch, const CIterator &i) const; diff --git a/src/coreclr/inc/sstring.inl b/src/coreclr/inc/sstring.inl index 03fc26fe9666c..0d48c5a181db4 100644 --- a/src/coreclr/inc/sstring.inl +++ b/src/coreclr/inc/sstring.inl @@ -651,6 +651,25 @@ inline const WCHAR *SString::GetUnicode() const SS_RETURN GetRawUnicode(); } +// Get a const pointer to the internal buffer as a UTF8 string. +inline const UTF8 *SString::GetUTF8() const +{ + SS_CONTRACT(const UTF8 *) + { + GC_NOTRIGGER; + PRECONDITION(CheckPointer(this)); + SS_POSTCONDITION(CheckPointer(RETVAL)); + if (IsRepresentation(REPRESENTATION_UTF8)) NOTHROW; else THROWS; + GC_NOTRIGGER; + SUPPORTS_DAC; + } + SS_CONTRACT_END; + + ConvertToUTF8(); + + SS_RETURN GetRawUTF8(); +} + // Normalize the string to unicode. This will make many operations nonfailing. inline void SString::Normalize() const { @@ -1906,44 +1925,6 @@ inline void SString::ConvertToIteratable() const SS_RETURN; } -//----------------------------------------------------------------------------- -// Create iterators on the string. -//----------------------------------------------------------------------------- - -inline SString::UIterator SString::BeginUnicode() -{ - SS_CONTRACT(SString::UIterator) - { - GC_NOTRIGGER; - PRECONDITION(CheckPointer(this)); - SS_POSTCONDITION(CheckValue(RETVAL)); - THROWS; - } - SS_CONTRACT_END; - - ConvertToUnicode(); - EnsureWritable(); - - SS_RETURN UIterator(this, 0); -} - -inline SString::UIterator SString::EndUnicode() -{ - SS_CONTRACT(SString::UIterator) - { - GC_NOTRIGGER; - PRECONDITION(CheckPointer(this)); - SS_POSTCONDITION(CheckValue(RETVAL)); - THROWS; - } - SS_CONTRACT_END; - - ConvertToUnicode(); - EnsureWritable(); - - SS_RETURN UIterator(this, GetCount()); -} - //----------------------------------------------------------------------------- // Create CIterators on the string. //----------------------------------------------------------------------------- @@ -2135,74 +2116,6 @@ inline WCHAR SString::Index::operator[](int index) const return *(WCHAR*)&GetAt(index); } -//----------------------------------------------------------------------------- -// Iterator support routines -//----------------------------------------------------------------------------- - -inline SString::UIndex::UIndex() -{ - LIMITED_METHOD_CONTRACT; -} - -inline SString::UIndex::UIndex(SString *string, SCOUNT_T index) - : SBuffer::Index(string, index*sizeof(WCHAR)) -{ - SS_CONTRACT_VOID - { - GC_NOTRIGGER; - PRECONDITION(CheckPointer(string)); - PRECONDITION(string->IsRepresentation(REPRESENTATION_UNICODE)); - PRECONDITION(DoCheck(0)); - SS_POSTCONDITION(CheckPointer(this)); - NOTHROW; - CANNOT_TAKE_LOCK; - } - SS_CONTRACT_END; - - SS_RETURN; -} - -inline WCHAR &SString::UIndex::GetAt(SCOUNT_T delta) const -{ - LIMITED_METHOD_CONTRACT; - - return ((WCHAR*)m_ptr)[delta]; -} - -inline void SString::UIndex::Skip(SCOUNT_T delta) -{ - LIMITED_METHOD_CONTRACT; - - m_ptr += delta * sizeof(WCHAR); -} - -inline SCOUNT_T SString::UIndex::Subtract(const UIndex &i) const -{ - WRAPPER_NO_CONTRACT; - - return (SCOUNT_T) (GetUnicode() - i.GetUnicode()); -} - -inline CHECK SString::UIndex::DoCheck(SCOUNT_T delta) const -{ - CANNOT_HAVE_CONTRACT; -#if _DEBUG - const SString *string = (const SString *) GetContainerDebug(); - - CHECK(GetUnicode() + delta >= string->GetRawUnicode()); - CHECK(GetUnicode() + delta <= string->GetRawUnicode() + string->GetCount()); -#endif - - CHECK_OK; -} - -inline WCHAR *SString::UIndex::GetUnicode() const -{ - LIMITED_METHOD_CONTRACT; - - return (WCHAR*) m_ptr; -} - //----------------------------------------------------------------------------- // Opaque scratch buffer class routines //----------------------------------------------------------------------------- diff --git a/src/coreclr/inc/static_assert.h b/src/coreclr/inc/static_assert.h index e344e83baca55..67336e1290394 100644 --- a/src/coreclr/inc/static_assert.h +++ b/src/coreclr/inc/static_assert.h @@ -14,12 +14,6 @@ #ifndef __STATIC_ASSERT_H__ #define __STATIC_ASSERT_H__ -// static_assert( cond, msg ) is now a compiler-supported intrinsic in Dev10 C++ compiler. -// Replaces previous uses of STATIC_ASSERT_MSG and COMPILE_TIME_ASSERT_MSG. - -// Replaces previous uses of CPP_ASSERT -#define static_assert_n( n, cond ) static_assert( cond, #cond ) - // Replaces previous uses of C_ASSERT and COMPILE_TIME_ASSERT #define static_assert_no_msg( cond ) static_assert( cond, #cond ) diff --git a/src/coreclr/inc/switches.h b/src/coreclr/inc/switches.h index d3fe1d636440d..9ec7e3cf05efd 100644 --- a/src/coreclr/inc/switches.h +++ b/src/coreclr/inc/switches.h @@ -53,7 +53,7 @@ #if defined(TARGET_X86) || defined(TARGET_ARM) #define USE_LAZY_PREFERRED_RANGE 0 -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X) || defined(TARGET_LOONGARCH64) +#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X) || defined(TARGET_LOONGARCH64) || defined(TARGET_POWERPC64) #if defined(HOST_UNIX) // In PAL we have a smechanism that reserves memory on start up that is diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index 7191833998d4d..f9444ab439ae6 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -3808,14 +3808,6 @@ inline bool FitsInRel28(INT64 val64) return (val64 >= -0x08000000LL) && (val64 < 0x08000000LL); } -//***************************************************************************** -// Splits a command line into argc/argv lists, using the VC7 parsing rules. -// This functions interface mimics the CommandLineToArgvW api. -// If function fails, returns NULL. -// If function suceeds, call delete [] on return pointer when done. -//***************************************************************************** -LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs); - // // TEB access can be dangerous when using fibers because a fiber may // run on multiple threads. If the TEB pointer is retrieved and saved @@ -3840,11 +3832,6 @@ class ClrTeb return (void *)(size_t)GetCurrentThreadId(); } - static void* InvalidFiberPtrId() - { - return NULL; - } - static void* GetStackBase() { return PAL_GetStackBase(); @@ -3877,33 +3864,12 @@ class ClrTeb return NtCurrentTeb()->NtTib.StackLimit; } - // Please don't start to use this method unless you absolutely have to. - // The reason why this is added is for WIN64 to support LEGACY PE-style TLS - // variables. On X86 it is supported by the JIT compilers themselves. On - // WIN64 we build more logic into the JIT helper for accessing fields. - static void* GetLegacyThreadLocalStoragePointer() - { - LIMITED_METHOD_CONTRACT; - return NtCurrentTeb()->ThreadLocalStoragePointer; - } - static void* GetOleReservedPtr() { LIMITED_METHOD_CONTRACT; return NtCurrentTeb()->ReservedForOle; } - static void* GetProcessEnvironmentBlock() - { - LIMITED_METHOD_CONTRACT; - return NtCurrentTeb()->ProcessEnvironmentBlock; - } - - - static void* InvalidFiberPtrId() - { - return (void*) 1; - } #endif // HOST_UNIX }; diff --git a/src/coreclr/inc/volatile.h b/src/coreclr/inc/volatile.h index dcfc8af4b329e..5f3f7491facef 100644 --- a/src/coreclr/inc/volatile.h +++ b/src/coreclr/inc/volatile.h @@ -68,8 +68,8 @@ #error The Volatile type is currently only defined for Visual C++ and GNU C++ #endif -#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_S390X) -#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM, ARM64, LOONGARCH64, or S390X CPUs +#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_S390X) && !defined(HOST_POWERPC64) +#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM, ARM64, LOONGARCH64, PPC64LE, or S390X CPUs #endif #if defined(__GNUC__) diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index 4bc1693e8dfb7..3410747d021eb 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -48,6 +48,9 @@ function(create_standalone_jit) elseif(TARGETDETAILS_ARCH STREQUAL "s390x") set(JIT_ARCH_SOURCES ${JIT_S390X_SOURCES}) set(JIT_ARCH_HEADERS ${JIT_S390X_HEADERS}) + elseif(TARGETDETAILS_ARCH STREQUAL "ppc64le") + set(JIT_ARCH_SOURCES ${JIT_POWERPC64_SOURCES}) + set(JIT_ARCH_HEADERS ${JIT_POWERPC64_HEADERS}) elseif(TARGETDETAILS_ARCH STREQUAL "loongarch64") set(JIT_ARCH_SOURCES ${JIT_LOONGARCH64_SOURCES}) set(JIT_ARCH_HEADERS ${JIT_LOONGARCH64_HEADERS}) @@ -241,6 +244,10 @@ set( JIT_S390X_SOURCES # Not supported as JIT target ) +set( JIT_POWERPC64_SOURCES + # Not supported as JIT target +) + set( JIT_LOONGARCH64_SOURCES codegenloongarch64.cpp emitloongarch64.cpp @@ -396,6 +403,10 @@ set ( JIT_S390X_HEADERS # Not supported as JIT target ) +set ( JIT_POWERPC64_HEADERS + # Not supported as JIT target +) + set( JIT_LOONGARCH64_HEADERS emitloongarch64.h emitfmtsloongarch64.h @@ -442,6 +453,9 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64) elseif(CLR_CMAKE_TARGET_ARCH_S390X) set(JIT_ARCH_SOURCES ${JIT_S390X_SOURCES}) set(JIT_ARCH_HEADERS ${JIT_S390X_HEADERS}) +elseif(CLR_CMAKE_TARGET_ARCH_POWERPC64) + set(JIT_ARCH_SOURCES ${JIT_POWERPC64_SOURCES}) + set(JIT_ARCH_HEADERS ${JIT_POWERPC64_HEADERS}) elseif(CLR_CMAKE_TARGET_ARCH_LOONGARCH64) set(JIT_ARCH_SOURCES ${JIT_LOONGARCH64_SOURCES}) set(JIT_ARCH_HEADERS ${JIT_LOONGARCH64_HEADERS}) @@ -600,13 +614,13 @@ if (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX) endif (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX) if (CLR_CMAKE_TARGET_UNIX) - if (NOT ARCH_TARGET_NAME STREQUAL s390x AND NOT ARCH_TARGET_NAME STREQUAL armv6) + if (NOT ARCH_TARGET_NAME STREQUAL s390x AND NOT ARCH_TARGET_NAME STREQUAL armv6 AND NOT ARCH_TARGET_NAME STREQUAL ppc64le) if(CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64) install_clr(TARGETS clrjit_universal_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit) else() install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit) endif() - endif(NOT ARCH_TARGET_NAME STREQUAL s390x AND NOT ARCH_TARGET_NAME STREQUAL armv6) + endif(NOT ARCH_TARGET_NAME STREQUAL s390x AND NOT ARCH_TARGET_NAME STREQUAL armv6 AND NOT ARCH_TARGET_NAME STREQUAL ppc64le) endif() if (CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_PGO_INSTRUMENT) diff --git a/src/coreclr/jit/ClrJit.PAL.exports b/src/coreclr/jit/ClrJit.PAL.exports index 2625e98bc421e..e4e6064db84e8 100644 --- a/src/coreclr/jit/ClrJit.PAL.exports +++ b/src/coreclr/jit/ClrJit.PAL.exports @@ -1,4 +1,5 @@ getJit jitStartup getLikelyClasses +getLikelyMethods jitBuildString diff --git a/src/coreclr/jit/ClrJit.exports b/src/coreclr/jit/ClrJit.exports index c6a22db4cae40..5430f7b165929 100644 --- a/src/coreclr/jit/ClrJit.exports +++ b/src/coreclr/jit/ClrJit.exports @@ -5,4 +5,5 @@ EXPORTS getJit jitStartup getLikelyClasses + getLikelyMethods jitBuildString diff --git a/src/coreclr/jit/ICorJitInfo_API_names.h b/src/coreclr/jit/ICorJitInfo_API_names.h index 520315b89f82a..2549835cefbf8 100644 --- a/src/coreclr/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/jit/ICorJitInfo_API_names.h @@ -10,6 +10,7 @@ DEF_CLR_API(setMethodAttribs) DEF_CLR_API(getMethodSig) DEF_CLR_API(getMethodInfo) DEF_CLR_API(canInline) +DEF_CLR_API(beginInlining) DEF_CLR_API(reportInliningDecision) DEF_CLR_API(canTailCall) DEF_CLR_API(reportTailCallDecision) diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index e65d1be26b3a0..f6a7b39b1590a 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -69,6 +69,15 @@ CorInfoInline WrapICorJitInfo::canInline( return temp; } +void WrapICorJitInfo::beginInlining( + CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + API_ENTER(beginInlining); + wrapHnd->beginInlining(inlinerHnd, inlineeHnd); + API_LEAVE(beginInlining); +} + void WrapICorJitInfo::reportInliningDecision( CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index ddee8ba3e6e1b..ccade20df0fbc 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -1344,12 +1344,12 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, if (op1->gtGetOp2()->IsCnsIntOrI()) { offset += op1->gtGetOp2()->AsIntCon()->gtIconVal; - op1 = op1->gtGetOp1(); + op1 = op1->gtGetOp1()->gtEffectiveVal(/* commaOnly */ true); } else if (op1->gtGetOp1()->IsCnsIntOrI()) { offset += op1->gtGetOp1()->AsIntCon()->gtIconVal; - op1 = op1->gtGetOp2(); + op1 = op1->gtGetOp2()->gtEffectiveVal(/* commaOnly */ true); } else { @@ -1431,9 +1431,6 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, assertion.op2.vn = ValueNumStore::VNForNull(); assertion.op2.u1.iconVal = 0; assertion.op2.u1.iconFlags = GTF_EMPTY; -#ifdef TARGET_64BIT - assertion.op2.u1.iconFlags |= GTF_ASSERTION_PROP_LONG; // Signify that this is really TYP_LONG -#endif // TARGET_64BIT } // // Are we making an assertion about a local variable? @@ -1568,13 +1565,6 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, #endif // TARGET_ARM assertion.op2.u1.iconVal = op2->AsIntCon()->gtIconVal; assertion.op2.u1.iconFlags = op2->GetIconHandleFlag(); -#ifdef TARGET_64BIT - if (op2->TypeGet() == TYP_LONG || op2->TypeGet() == TYP_BYREF) - { - assertion.op2.u1.iconFlags |= - GTF_ASSERTION_PROP_LONG; // Signify that this is really TYP_LONG - } -#endif // TARGET_64BIT } else if (op2->gtOper == GT_CNS_LNG) { @@ -1731,12 +1721,6 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */ assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0); assertion.op2.u1.iconFlags = iconFlags; -#ifdef TARGET_64BIT - if (op2->AsOp()->gtOp1->TypeGet() == TYP_LONG) - { - assertion.op2.u1.iconFlags |= GTF_ASSERTION_PROP_LONG; // Signify that this is really TYP_LONG - } -#endif // TARGET_64BIT } // JIT case else if (optIsTreeKnownIntValue(!optLocalAssertionProp, op2, &cnsValue, &iconFlags)) @@ -1749,12 +1733,6 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1, /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */ assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0); assertion.op2.u1.iconFlags = iconFlags; -#ifdef TARGET_64BIT - if (op2->TypeGet() == TYP_LONG) - { - assertion.op2.u1.iconFlags |= GTF_ASSERTION_PROP_LONG; // Signify that this is really TYP_LONG - } -#endif // TARGET_64BIT } else { @@ -2047,13 +2025,9 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion) case O2K_IND_CNS_INT: case O2K_CONST_INT: { -// The only flags that can be set are those in the GTF_ICON_HDL_MASK, or GTF_ASSERTION_PROP_LONG, which is -// used to indicate a long constant. -#ifdef TARGET_64BIT - assert((assertion->op2.u1.iconFlags & ~(GTF_ICON_HDL_MASK | GTF_ASSERTION_PROP_LONG)) == 0); -#else + // The only flags that can be set are those in the GTF_ICON_HDL_MASK. assert((assertion->op2.u1.iconFlags & ~GTF_ICON_HDL_MASK) == 0); -#endif + switch (assertion->op1.kind) { case O1K_EXACT_TYPE: @@ -3177,6 +3151,15 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) if (conValTree != nullptr) { + if (tree->OperIs(GT_LCL_VAR)) + { + if (!optIsProfitableToSubstitute(tree->AsLclVar(), block, conValTree)) + { + // Not profitable to substitute + return nullptr; + } + } + // Were able to optimize. conValTree->gtVNPair = vnPair; GenTree* sideEffList = optExtractSideEffListFromConst(tree); @@ -3199,6 +3182,55 @@ GenTree* Compiler::optVNConstantPropOnTree(BasicBlock* block, GenTree* tree) } } +//------------------------------------------------------------------------------ +// optIsProfitableToSubstitute: Checks if value worth substituting to lcl location +// +// Arguments: +// lcl - lcl to replace with value if profitable +// lclBlock - Basic block lcl located in +// value - value we plan to substitute to lcl +// +// Returns: +// False if it's likely not profitable to do substitution, True otherwise +// +bool Compiler::optIsProfitableToSubstitute(GenTreeLclVarCommon* lcl, BasicBlock* lclBlock, GenTree* value) +{ + // A simple heuristic: If the constant is defined outside of a loop (not far from its head) + // and is used inside it - don't propagate. + + // TODO: Extend on more kinds of trees + if (!value->OperIs(GT_CNS_VEC, GT_CNS_DBL)) + { + return true; + } + + gtPrepareCost(value); + + if ((value->GetCostEx() > 1) && (value->GetCostSz() > 1)) + { + // Try to find the block this constant was originally defined in + if (lcl->HasSsaName()) + { + BasicBlock* defBlock = lvaGetDesc(lcl)->GetPerSsaData(lcl->GetSsaNum())->GetBlock(); + if (defBlock != nullptr) + { + // Avoid propagating if the weighted use cost is significantly greater than the def cost. + // NOTE: this currently does not take "a float living across a call" case into account + // where we might end up with spill/restore on ABIs without callee-saved registers + const weight_t defBlockWeight = defBlock->getBBWeight(this); + const weight_t lclblockWeight = lclBlock->getBBWeight(this); + + if ((defBlockWeight > 0) && ((lclblockWeight / defBlockWeight) >= BB_LOOP_WEIGHT_SCALE)) + { + JITDUMP("Constant propagation inside loop " FMT_BB " is not profitable\n", lclBlock->bbNum); + return false; + } + } + } + } + return true; +} + //------------------------------------------------------------------------------ // optConstantAssertionProp: Possibly substitute a constant for a local use // diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h index 88dcb79794fb8..e9a539a2f35fa 100644 --- a/src/coreclr/jit/block.h +++ b/src/coreclr/jit/block.h @@ -526,32 +526,32 @@ enum BasicBlockFlags : unsigned __int64 #endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) - BBF_BACKWARD_JUMP = MAKE_BBFLAG(24), // BB is surrounded by a backward jump/switch arc - BBF_RETLESS_CALL = MAKE_BBFLAG(25), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired - // BBJ_ALWAYS); see isBBCallAlwaysPair(). - BBF_LOOP_PREHEADER = MAKE_BBFLAG(26), // BB is a loop preheader block - BBF_COLD = MAKE_BBFLAG(27), // BB is cold - - BBF_PROF_WEIGHT = MAKE_BBFLAG(28), // BB weight is computed from profile data - BBF_IS_LIR = MAKE_BBFLAG(29), // Set if the basic block contains LIR (as opposed to HIR) - BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(30), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind - // as BBJ_ALWAYS. Used for the paired BBJ_ALWAYS block following the - // BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a - // finally. - BBF_CLONED_FINALLY_BEGIN = MAKE_BBFLAG(31), // First block of a cloned finally region - - BBF_CLONED_FINALLY_END = MAKE_BBFLAG(32), // Last block of a cloned finally region - BBF_HAS_CALL = MAKE_BBFLAG(33), // BB contains a call + BBF_BACKWARD_JUMP = MAKE_BBFLAG(24), // BB is surrounded by a backward jump/switch arc + BBF_RETLESS_CALL = MAKE_BBFLAG(25), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired + // BBJ_ALWAYS); see isBBCallAlwaysPair(). + BBF_LOOP_PREHEADER = MAKE_BBFLAG(26), // BB is a loop preheader block + BBF_COLD = MAKE_BBFLAG(27), // BB is cold + + BBF_PROF_WEIGHT = MAKE_BBFLAG(28), // BB weight is computed from profile data + BBF_IS_LIR = MAKE_BBFLAG(29), // Set if the basic block contains LIR (as opposed to HIR) + BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(30), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind + // as BBJ_ALWAYS. Used for the paired BBJ_ALWAYS block following the + // BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a + // finally. + BBF_CLONED_FINALLY_BEGIN = MAKE_BBFLAG(31), // First block of a cloned finally region + + BBF_CLONED_FINALLY_END = MAKE_BBFLAG(32), // Last block of a cloned finally region + BBF_HAS_CALL = MAKE_BBFLAG(33), // BB contains a call BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY = MAKE_BBFLAG(34), // Block is dominated by exceptional entry. - BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(35), // Block is a target of a backward jump + BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(35), // Block is a target of a backward jump - BBF_PATCHPOINT = MAKE_BBFLAG(36), // Block is a patchpoint - BBF_HAS_CLASS_PROFILE = MAKE_BBFLAG(37), // BB contains a call needing a class profile - BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(38), // Block is a partial compilation patchpoint - BBF_HAS_ALIGN = MAKE_BBFLAG(39), // BB ends with 'align' instruction - BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(40), // BB has pred that has potential tail call + BBF_PATCHPOINT = MAKE_BBFLAG(36), // Block is a patchpoint + BBF_HAS_HISTOGRAM_PROFILE = MAKE_BBFLAG(37), // BB contains a call needing a histogram profile + BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(38), // Block is a partial compilation patchpoint + BBF_HAS_ALIGN = MAKE_BBFLAG(39), // BB ends with 'align' instruction + BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(40), // BB has pred that has potential tail call - BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(41), // Block is a source of a backward jump + BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(41), // Block is a source of a backward jump // The following are sets of flags. @@ -582,7 +582,7 @@ enum BasicBlockFlags : unsigned __int64 // TODO: Should BBF_RUN_RARELY be added to BBF_SPLIT_GAINED ? BBF_SPLIT_GAINED = BBF_DONT_REMOVE | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_NEWARRAY | BBF_PROF_WEIGHT | \ - BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | BBF_HAS_CLASS_PROFILE, + BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | BBF_HAS_HISTOGRAM_PROFILE, }; inline constexpr BasicBlockFlags operator ~(BasicBlockFlags a) @@ -918,8 +918,8 @@ struct BasicBlock : private LIR::Range }; union { - unsigned bbStkTempsOut; // base# for output stack temps - int bbClassSchemaIndex; // schema index for class instrumentation + unsigned bbStkTempsOut; // base# for output stack temps + int bbHistogramSchemaIndex; // schema index for histogram instrumentation }; #define MAX_XCPTN_INDEX (USHRT_MAX - 1) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 8646d9191edcf..c294957a0cd2c 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -642,6 +642,7 @@ class CodeGen final : public CodeGenInterface virtual void SetSaveFpLrWithAllCalleeSavedRegisters(bool value); virtual bool IsSaveFpLrWithAllCalleeSavedRegisters() const; bool genSaveFpLrWithAllCalleeSavedRegisters; + bool genForceFuncletFrameType5; #endif // TARGET_ARM64 //------------------------------------------------------------------------- @@ -1335,10 +1336,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genPutStructArgStk(GenTreePutArgStk* treeNode); - unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset); - unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset); - unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset); - unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset); + unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset); + unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset); + unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset); + unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* src, unsigned offset); void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset); void genStoreRegToStackArg(var_types type, regNumber reg, int offset); void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode); diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 2b9d4be0abc7d..b13c11c50d668 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -186,6 +186,7 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog) JITDUMP("Frame type 5 (save FP/LR at top). #outsz=%d; #framesz=%d; localloc? %s\n", unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, dspBool(compiler->compLocallocUsed)); + assert(genSaveFpLrWithAllCalleeSavedRegisters); assert((calleeSaveSpOffset == 0) || (calleeSaveSpOffset == REGSIZE_BYTES)); // Restore sp from fp: @@ -1077,10 +1078,14 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP + * | OSR padding | // If required + * |-----------------------| * | Varargs regs space | // Only for varargs main functions; 64 bytes * |-----------------------| * |Callee saved registers | // multiple of 8 bytes * |-----------------------| + * | MonitorAcquired | // 8 bytes; for synchronized methods + * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned. @@ -1104,10 +1109,14 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP + * | OSR padding | // If required + * |-----------------------| * | Varargs regs space | // Only for varargs main functions; 64 bytes * |-----------------------| * |Callee saved registers | // multiple of 8 bytes * |-----------------------| + * | MonitorAcquired | // 8 bytes; for synchronized methods + * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned. @@ -1134,20 +1143,24 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP + * | OSR padding | // If required + * |-----------------------| * | Varargs regs space | // Only for varargs main functions; 64 bytes * |-----------------------| * |Callee saved registers | // multiple of 8 bytes * |-----------------------| + * | MonitorAcquired | // 8 bytes; for synchronized methods + * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| * ~ alignment padding ~ // To make the first SP subtraction 16 byte aligned * |-----------------------| - * | Saved FP, LR | // 16 bytes + * | Saved FP, LR | // 16 bytes <-- SP after first adjustment (points at saved FP) * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned (specifically, to 16-byte align the outgoing argument space). * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes - * |-----------------------| <---- Ambient SP + * |-----------------------| <---- Ambient SP (SP after second adjustment) * | | | * ~ | Stack grows ~ * | | downward | @@ -1162,7 +1175,7 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * 8 float callee-saved registers v8-v15 * 8 saved integer argument registers x0-x7, if varargs function * 1 PSP slot - * 1 alignment slot + * 1 alignment slot or monitor acquired slot * == 30 slots * 8 bytes = 240 bytes. * * The outgoing argument size, however, can be very large, if we call a function that takes a large number of @@ -1198,6 +1211,8 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP + * | OSR padding | // If required + * |-----------------------| * | Varargs regs space | // Only for varargs main functions; 64 bytes * |-----------------------| * | Saved LR | // 8 bytes @@ -1206,6 +1221,8 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * |Callee saved registers | // multiple of 8 bytes * |-----------------------| + * | MonitorAcquired | // 8 bytes; for synchronized methods + * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned. @@ -1235,6 +1252,8 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * | incoming arguments | * +=======================+ <---- Caller's SP + * | OSR padding | // If required + * |-----------------------| * | Varargs regs space | // Only for varargs main functions; 64 bytes * |-----------------------| * | Saved LR | // 8 bytes @@ -1243,14 +1262,16 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * |-----------------------| * |Callee saved registers | // multiple of 8 bytes * |-----------------------| + * | MonitorAcquired | // 8 bytes; for synchronized methods + * |-----------------------| * | PSP slot | // 8 bytes (omitted in NativeAOT ABI) * |-----------------------| - * ~ alignment padding ~ // To make the first SP subtraction 16 byte aligned + * ~ alignment padding ~ // To make the first SP subtraction 16 byte aligned <-- SP after first adjustment (points at alignment padding or PSP slot) * |-----------------------| * ~ alignment padding ~ // To make the whole frame 16 byte aligned (specifically, to 16-byte align the outgoing argument space). * |-----------------------| * | Outgoing arg space | // multiple of 8 bytes - * |-----------------------| <---- Ambient SP + * |-----------------------| <---- Ambient SP (SP after second adjustment) * | | | * ~ | Stack grows ~ * | | downward | @@ -1310,6 +1331,8 @@ void CodeGen::genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, in * ldp fp,lr,[sp],#framesz * ret lr * + * See CodeGen::genPushCalleeSavedRegisters() for a description of the main function frame layout. + * See Compiler::lvaAssignVirtualFrameOffsetsToLocals() for calculation of main frame local variable offsets. */ // clang-format on @@ -1354,10 +1377,12 @@ void CodeGen::genFuncletProlog(BasicBlock* block) if (genFuncletInfo.fiFrameType == 1) { - // With OSR we may see large values for fiSpDelta1 - // (we really need to probe the frame, sigh) if (compiler->opts.IsOSR()) { + // With OSR we may see large values for fiSpDelta1. + // We repurpose genAllocLclFram to do the necessary probing. + bool scratchRegIsZero = false; + genAllocLclFrame(-genFuncletInfo.fiSpDelta1, REG_SCRATCH, &scratchRegIsZero, maskArgRegsLiveIn); genStackPointerAdjustment(genFuncletInfo.fiSpDelta1, REG_SCRATCH, nullptr, /* reportUnwindData */ true); GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, 0); compiler->unwindSaveRegPair(REG_FP, REG_LR, 0); @@ -1393,10 +1418,12 @@ void CodeGen::genFuncletProlog(BasicBlock* block) } else if (genFuncletInfo.fiFrameType == 3) { - // With OSR we may see large values for fiSpDelta1 - // (we really need to probe the frame, sigh) if (compiler->opts.IsOSR()) { + // With OSR we may see large values for fiSpDelta1 + // We repurpose genAllocLclFram to do the necessary probing. + bool scratchRegIsZero = false; + genAllocLclFrame(-genFuncletInfo.fiSpDelta1, REG_SCRATCH, &scratchRegIsZero, maskArgRegsLiveIn); genStackPointerAdjustment(genFuncletInfo.fiSpDelta1, REG_SCRATCH, nullptr, /* reportUnwindData */ true); GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, 0); compiler->unwindSaveRegPair(REG_FP, REG_LR, 0); @@ -1427,11 +1454,17 @@ void CodeGen::genFuncletProlog(BasicBlock* block) if (compiler->opts.IsOSR()) { + // With OSR we may see large values for fiSpDelta1. + // We repurpose genAllocLclFram to do the necessary probing. + bool scratchRegIsZero = false; + genAllocLclFrame(-genFuncletInfo.fiSpDelta1, REG_SCRATCH, &scratchRegIsZero, maskArgRegsLiveIn); genStackPointerAdjustment(genFuncletInfo.fiSpDelta1, REG_SCRATCH, nullptr, /* reportUnwindData */ true); } else { - // Nothing to do here; the first SP adjustment will be done by saving the callee-saved registers. + assert(genFuncletInfo.fiSpDelta1 < 0); + assert(genFuncletInfo.fiSpDelta1 >= -240); + genStackPointerAdjustment(genFuncletInfo.fiSpDelta1, REG_NA, nullptr, /* reportUnwindData */ true); } } @@ -1501,6 +1534,8 @@ void CodeGen::genFuncletProlog(BasicBlock* block) /***************************************************************************** * * Generates code for an EH funclet epilog. + * + * See the description of frame shapes at genFuncletProlog(). */ void CodeGen::genFuncletEpilog() @@ -1675,6 +1710,9 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() if (compiler->opts.IsOSR() && (PSPSize > 0)) { osrPad = compiler->info.compPatchpointInfo->TotalFrameSize(); + + // OSR pad must be already aligned to stack size. + assert((osrPad % STACK_ALIGN) == 0); } genFuncletInfo.fiFunction_CallerSP_to_FP_delta = genCallerSPtoFPdelta() - osrPad; @@ -1705,31 +1743,41 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() assert(compiler->lvaOutgoingArgSpaceSize % REGSIZE_BYTES == 0); unsigned const outgoingArgSpaceAligned = roundUp(compiler->lvaOutgoingArgSpaceSize, STACK_ALIGN); - unsigned const maxFuncletFrameSizeAligned = saveRegsPlusPSPSizeAligned + osrPad + outgoingArgSpaceAligned; - assert((maxFuncletFrameSizeAligned % STACK_ALIGN) == 0); + // If do two SP adjustments, each one must be aligned. This represents the largest possible stack size, if two + // separate alignment slots are required. + unsigned const twoSpAdjustmentFuncletFrameSizeAligned = + osrPad + saveRegsPlusPSPSizeAligned + outgoingArgSpaceAligned; + assert((twoSpAdjustmentFuncletFrameSizeAligned % STACK_ALIGN) == 0); int SP_to_FPLR_save_delta; int SP_to_PSP_slot_delta; int CallerSP_to_PSP_slot_delta; - unsigned const funcletFrameSize = saveRegsPlusPSPSize + osrPad + compiler->lvaOutgoingArgSpaceSize; - unsigned const funcletFrameSizeAligned = roundUp(funcletFrameSize, STACK_ALIGN); - assert(funcletFrameSizeAligned <= maxFuncletFrameSizeAligned); - - unsigned const funcletFrameAlignmentPad = funcletFrameSizeAligned - funcletFrameSize; - assert((funcletFrameAlignmentPad == 0) || (funcletFrameAlignmentPad == REGSIZE_BYTES)); + // Are we stressing frame type 5? Don't do it unless we have non-zero outgoing arg space. + const bool useFrameType5 = + genSaveFpLrWithAllCalleeSavedRegisters && genForceFuncletFrameType5 && (compiler->lvaOutgoingArgSpaceSize > 0); - if (maxFuncletFrameSizeAligned <= 512) + if ((twoSpAdjustmentFuncletFrameSizeAligned <= 512) && !useFrameType5) { + unsigned const oneSpAdjustmentFuncletFrameSize = + osrPad + saveRegsPlusPSPSize + compiler->lvaOutgoingArgSpaceSize; + unsigned const oneSpAdjustmentFuncletFrameSizeAligned = roundUp(oneSpAdjustmentFuncletFrameSize, STACK_ALIGN); + assert(oneSpAdjustmentFuncletFrameSizeAligned <= twoSpAdjustmentFuncletFrameSizeAligned); + + unsigned const oneSpAdjustmentFuncletFrameSizeAlignmentPad = + oneSpAdjustmentFuncletFrameSizeAligned - oneSpAdjustmentFuncletFrameSize; + assert((oneSpAdjustmentFuncletFrameSizeAlignmentPad == 0) || + (oneSpAdjustmentFuncletFrameSizeAlignmentPad == REGSIZE_BYTES)); + if (genSaveFpLrWithAllCalleeSavedRegisters) { - SP_to_FPLR_save_delta = funcletFrameSizeAligned - (2 /* FP, LR */ * REGSIZE_BYTES); + SP_to_FPLR_save_delta = oneSpAdjustmentFuncletFrameSizeAligned - (2 /* FP, LR */ * REGSIZE_BYTES); if (compiler->info.compIsVarArgs) { SP_to_FPLR_save_delta -= MAX_REG_ARG * REGSIZE_BYTES; } - SP_to_PSP_slot_delta = compiler->lvaOutgoingArgSpaceSize + funcletFrameAlignmentPad + osrPad; + SP_to_PSP_slot_delta = compiler->lvaOutgoingArgSpaceSize + oneSpAdjustmentFuncletFrameSizeAlignmentPad; CallerSP_to_PSP_slot_delta = -(int)(osrPad + saveRegsPlusPSPSize); genFuncletInfo.fiFrameType = 4; @@ -1737,7 +1785,8 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() else { SP_to_FPLR_save_delta = compiler->lvaOutgoingArgSpaceSize; - SP_to_PSP_slot_delta = SP_to_FPLR_save_delta + 2 /* FP, LR */ * REGSIZE_BYTES + funcletFrameAlignmentPad; + SP_to_PSP_slot_delta = + SP_to_FPLR_save_delta + 2 /* FP, LR */ * REGSIZE_BYTES + oneSpAdjustmentFuncletFrameSizeAlignmentPad; CallerSP_to_PSP_slot_delta = -(int)(osrPad + saveRegsPlusPSPSize - 2 /* FP, LR */ * REGSIZE_BYTES); if (compiler->lvaOutgoingArgSpaceSize == 0) @@ -1750,26 +1799,25 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() } } - genFuncletInfo.fiSpDelta1 = -(int)funcletFrameSizeAligned; + genFuncletInfo.fiSpDelta1 = -(int)oneSpAdjustmentFuncletFrameSizeAligned; genFuncletInfo.fiSpDelta2 = 0; - assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)funcletFrameSizeAligned); + assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)oneSpAdjustmentFuncletFrameSizeAligned); } else { - unsigned saveRegsPlusPSPAlignmentPad = saveRegsPlusPSPSizeAligned - saveRegsPlusPSPSize; + unsigned const saveRegsPlusPSPAlignmentPad = saveRegsPlusPSPSizeAligned - saveRegsPlusPSPSize; assert((saveRegsPlusPSPAlignmentPad == 0) || (saveRegsPlusPSPAlignmentPad == REGSIZE_BYTES)); if (genSaveFpLrWithAllCalleeSavedRegisters) { - SP_to_FPLR_save_delta = funcletFrameSizeAligned - (2 /* FP, LR */ * REGSIZE_BYTES); + SP_to_FPLR_save_delta = twoSpAdjustmentFuncletFrameSizeAligned - (2 /* FP, LR */ * REGSIZE_BYTES); if (compiler->info.compIsVarArgs) { SP_to_FPLR_save_delta -= MAX_REG_ARG * REGSIZE_BYTES; } - SP_to_PSP_slot_delta = - compiler->lvaOutgoingArgSpaceSize + funcletFrameAlignmentPad + saveRegsPlusPSPAlignmentPad; + SP_to_PSP_slot_delta = outgoingArgSpaceAligned + saveRegsPlusPSPAlignmentPad; CallerSP_to_PSP_slot_delta = -(int)(osrPad + saveRegsPlusPSPSize); genFuncletInfo.fiFrameType = 5; @@ -1787,7 +1835,7 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() genFuncletInfo.fiSpDelta1 = -(int)(osrPad + saveRegsPlusPSPSizeAligned); genFuncletInfo.fiSpDelta2 = -(int)outgoingArgSpaceAligned; - assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)maxFuncletFrameSizeAligned); + assert(genFuncletInfo.fiSpDelta1 + genFuncletInfo.fiSpDelta2 == -(int)twoSpAdjustmentFuncletFrameSizeAligned); } /* Now save it for future use */ @@ -2178,7 +2226,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, { if (emitter::emitIns_valid_imm_for_mov(imm, size)) { - GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm); + GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm, INS_OPTS_NONE DEBUGARG(targetHandle) DEBUGARG(gtFlags)); } else { @@ -2224,7 +2272,9 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, imm16 = ~imm16; } - GetEmitter()->emitIns_R_I_I(ins, size, reg, imm16, i, INS_OPTS_LSL); + GetEmitter()->emitIns_R_I_I(ins, size, reg, imm16, i, + INS_OPTS_LSL DEBUGARG(i == 0 ? targetHandle : 0) + DEBUGARG(i == 0 ? gtFlags : GTF_EMPTY)); // Once the initial movz/movn is emitted the remaining instructions will all use movk ins = INS_movk; @@ -2258,8 +2308,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre { case GT_CNS_INT: { - GenTreeIntConCommon* con = tree->AsIntConCommon(); - ssize_t cnsVal = con->IconValue(); + GenTreeIntCon* con = tree->AsIntCon(); + ssize_t cnsVal = con->IconValue(); emitAttr attr = emitActualTypeSize(targetType); // TODO-CQ: Currently we cannot do this for all handles because of @@ -2275,8 +2325,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre } instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal, - INS_FLAGS_DONT_CARE DEBUGARG(tree->AsIntCon()->gtTargetHandle) - DEBUGARG(tree->AsIntCon()->gtFlags)); + INS_FLAGS_DONT_CARE DEBUGARG(con->gtTargetHandle) DEBUGARG(con->gtFlags)); regSet.verifyRegUsed(targetReg); } break; @@ -4527,6 +4576,19 @@ void CodeGen::SetSaveFpLrWithAllCalleeSavedRegisters(bool value) { JITDUMP("Setting genSaveFpLrWithAllCalleeSavedRegisters to %s\n", dspBool(value)); genSaveFpLrWithAllCalleeSavedRegisters = value; + + if (genSaveFpLrWithAllCalleeSavedRegisters) + { + // We'll use frame type 4 or 5. Frame type 5 only occurs if there is a very large outgoing argument + // space. This is extremely rare, so under stress force using this frame type. However, frame type 5 + // isn't used if there is no outgoing argument space; this is checked elsewhere. + + if ((compiler->opts.compJitSaveFpLrWithCalleeSavedRegisters == 3) || + compiler->compStressCompile(Compiler::STRESS_GENERIC_VARN, 50)) + { + genForceFuncletFrameType5 = true; + } + } } //--------------------------------------------------------------------- @@ -10281,18 +10343,34 @@ void CodeGen::genCodeForAddEx(GenTreeOp* tree) // void CodeGen::genCodeForCond(GenTreeOp* tree) { - assert(tree->OperIs(GT_CSNEG_MI)); - assert(!(tree->gtFlags & GTF_SET_FLAGS) && (tree->gtFlags & GTF_USE_FLAGS)); + assert(tree->OperIs(GT_CSNEG_MI, GT_CNEG_LT)); + assert(!(tree->gtFlags & GTF_SET_FLAGS)); genConsumeOperands(tree); - instruction ins; - insCond cond; switch (tree->OperGet()) { case GT_CSNEG_MI: { - ins = INS_csneg; - cond = INS_COND_MI; + instruction ins = INS_csneg; + insCond cond = INS_COND_MI; + + regNumber dstReg = tree->GetRegNum(); + regNumber op1Reg = tree->gtGetOp1()->GetRegNum(); + regNumber op2Reg = tree->gtGetOp2()->GetRegNum(); + + GetEmitter()->emitIns_R_R_R_COND(ins, emitActualTypeSize(tree), dstReg, op1Reg, op2Reg, cond); + break; + } + + case GT_CNEG_LT: + { + instruction ins = INS_cneg; + insCond cond = INS_COND_LT; + + regNumber dstReg = tree->GetRegNum(); + regNumber op1Reg = tree->gtGetOp1()->GetRegNum(); + + GetEmitter()->emitIns_R_R_COND(ins, emitActualTypeSize(tree), dstReg, op1Reg, cond); break; } @@ -10300,11 +10378,6 @@ void CodeGen::genCodeForCond(GenTreeOp* tree) unreached(); } - regNumber dstReg = tree->GetRegNum(); - regNumber op1Reg = tree->gtGetOp1()->GetRegNum(); - regNumber op2Reg = tree->gtGetOp2()->GetRegNum(); - - GetEmitter()->emitIns_R_R_R_COND(ins, emitActualTypeSize(tree), dstReg, op1Reg, op2Reg, cond); genProduceReg(tree); } diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index f5de40823259e..dd4c25c5f0763 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -324,6 +324,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) break; case GT_CSNEG_MI: + case GT_CNEG_LT: genCodeForCond(treeNode->AsOp()); break; #endif // TARGET_ARM64 @@ -770,9 +771,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) GenTree* source = treeNode->gtGetOp1(); - bool isStruct = source->TypeIs(TYP_STRUCT) || (source->OperGet() == GT_FIELD_LIST); - - if (!isStruct) // a normal non-Struct argument + if (!source->TypeIs(TYP_STRUCT)) // a normal non-Struct argument { if (varTypeIsSIMD(source->TypeGet())) { @@ -864,9 +863,9 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) { genPutArgStkFieldList(treeNode, varNumOut); } - else // We must have a GT_OBJ or a GT_LCL_VAR + else { - noway_assert(source->OperIs(GT_LCL_VAR, GT_OBJ)); + noway_assert(source->OperIsLocalRead() || source->OperIs(GT_OBJ)); var_types targetType = source->TypeGet(); noway_assert(varTypeIsStruct(targetType)); @@ -879,96 +878,42 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) #ifdef TARGET_ARM64 regNumber hiReg = treeNode->GetSingleTempReg(); #endif // TARGET_ARM64 - regNumber addrReg = REG_NA; - GenTreeLclVarCommon* varNode = nullptr; - GenTree* addrNode = nullptr; + GenTreeLclVarCommon* srcLclNode = nullptr; + regNumber addrReg = REG_NA; + ClassLayout* layout = nullptr; - if (source->OperGet() == GT_LCL_VAR) + // Setup "layout", "srcLclNode" and "addrReg". + if (source->OperIsLocalRead()) { - varNode = source->AsLclVarCommon(); + srcLclNode = source->AsLclVarCommon(); + layout = srcLclNode->GetLayout(compiler); + LclVarDsc* varDsc = compiler->lvaGetDesc(srcLclNode); + + // This struct must live on the stack frame. + assert(varDsc->lvOnFrame && !varDsc->lvRegister); } else // we must have a GT_OBJ { - assert(source->OperGet() == GT_OBJ); - - addrNode = source->AsOp()->gtOp1; + layout = source->AsObj()->GetLayout(); + addrReg = genConsumeReg(source->AsObj()->Addr()); - // addrNode can either be a GT_LCL_VAR_ADDR or an address expression - // - if (addrNode->OperGet() == GT_LCL_VAR_ADDR) +#ifdef TARGET_ARM64 + // If addrReg equal to loReg, swap(loReg, hiReg) + // This reduces code complexity by only supporting one addrReg overwrite case + if (loReg == addrReg) { - // We have a GT_OBJ(GT_LCL_VAR_ADDR) - // - // We will treat this case the same as above - // (i.e if we just had this GT_LCL_VAR directly as the source) - // so update 'source' to point this GT_LCL_VAR_ADDR node - // and continue to the codegen for the LCL_VAR node below - // - assert(addrNode->isContained()); - varNode = addrNode->AsLclVarCommon(); - addrNode = nullptr; + loReg = hiReg; + hiReg = addrReg; } - else // addrNode is used - { - // TODO-Cleanup: `Lowering::NewPutArg` marks only `LCL_VAR_ADDR` as contained nowadays, - // but we use `genConsumeAddress` as a precaution, use `genConsumeReg()` instead. - assert(!addrNode->isContained()); - // Generate code to load the address that we need into a register - genConsumeAddress(addrNode); - addrReg = addrNode->GetRegNum(); - -#ifdef TARGET_ARM64 - // If addrReg equal to loReg, swap(loReg, hiReg) - // This reduces code complexity by only supporting one addrReg overwrite case - if (loReg == addrReg) - { - loReg = hiReg; - hiReg = addrReg; - } #endif // TARGET_ARM64 - } } - // Either varNode or addrNOde must have been setup above, - // the xor ensures that only one of the two is setup, not both - assert((varNode != nullptr) ^ (addrNode != nullptr)); - - ClassLayout* layout; - unsigned srcSize; - bool isHfa; - - // Setup the srcSize, isHFa, and gcPtrCount - if (source->OperGet() == GT_LCL_VAR) - { - assert(varNode != nullptr); - LclVarDsc* varDsc = compiler->lvaGetDesc(varNode); - - // This struct also must live in the stack frame - // And it can't live in a register (SIMD) - assert(varDsc->lvType == TYP_STRUCT); - assert(varDsc->lvOnFrame && !varDsc->lvRegister); - - srcSize = varDsc->lvSize(); - isHfa = varDsc->lvIsHfa(); - layout = varDsc->GetLayout(); - } - else // we must have a GT_OBJ - { - assert(source->OperGet() == GT_OBJ); - - // If the source is an OBJ node then we need to use the type information - // it provides (size and GC layout) even if the node wraps a lclvar. Due - // to struct reinterpretation (e.g. Unsafe.As) it is possible that - // the OBJ node has a different type than the lclvar. - layout = source->AsObj()->GetLayout(); - srcSize = layout->GetSize(); - isHfa = compiler->IsHfa(layout->GetClassHandle()); - } + unsigned srcSize = layout->GetSize(); // If we have an HFA we can't have any GC pointers, // if not then the max size for the struct is 16 bytes - if (isHfa) + if (compiler->IsHfa(layout->GetClassHandle())) { noway_assert(!layout->HasGCPtr()); } @@ -981,45 +926,32 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) noway_assert(srcSize <= MAX_PASS_MULTIREG_BYTES); #endif // TARGET_ARM64 - unsigned structSize; - unsigned dstSize = treeNode->GetStackByteSize(); - if (dstSize != srcSize) + + // We can generate smaller code if store size is a multiple of TARGET_POINTER_SIZE. + // The dst size can be rounded up to PUTARG_STK size. The src size can be rounded up + // if it reads a local variable because reading "too much" from a local cannot fault. + // We must also be careful to check for the arm64 apple case where arguments can be + // passed without padding. + // + if ((dstSize != srcSize) && (srcLclNode != nullptr)) { - // We can generate a smaller code if store size is a multiple of TARGET_POINTER_SIZE. - // The dst size can be rounded up to PUTARG_STK size. - // The src size can be rounded up if it reads a local variable slot because the local - // variable stack allocation size is rounded up to be a multiple of the TARGET_POINTER_SIZE. - // The exception is arm64 apple arguments because they can be passed without padding. - if (varNode != nullptr) + unsigned widenedSrcSize = roundUp(srcSize, TARGET_POINTER_SIZE); + if (widenedSrcSize <= dstSize) { - // If we have a varNode, even if it was casted using `OBJ`, we can read its original memory size. - const LclVarDsc* varDsc = compiler->lvaGetDesc(varNode); - const unsigned varStackSize = varDsc->lvSize(); - if (varStackSize >= srcSize) - { - srcSize = varStackSize; - } + srcSize = widenedSrcSize; } } - if (dstSize == srcSize) - { - structSize = dstSize; - } - else - { - // With Unsafe object cast we can have different strange combinations: - // PutArgStk<8>(Obj<16>(LclVar<8>)) -> copy 8 bytes; - // PutArgStk<16>(Obj<16>(LclVar<8>)) -> copy 16 bytes, reading undefined memory after the local. - structSize = min(dstSize, srcSize); - } - int remainingSize = structSize; + assert(srcSize <= dstSize); + + int remainingSize = srcSize; unsigned structOffset = 0; + unsigned lclOffset = (srcLclNode != nullptr) ? srcLclNode->GetLclOffs() : 0; unsigned nextIndex = 0; #ifdef TARGET_ARM64 - // For a >= 16-byte structSize we will generate a ldp and stp instruction each loop + // For a >= 16-byte sizes we will generate a ldp and stp instruction each loop // ldp x2, x3, [x0] // stp x2, x3, [sp, #16] @@ -1028,11 +960,11 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) var_types type0 = layout->GetGCPtrType(nextIndex + 0); var_types type1 = layout->GetGCPtrType(nextIndex + 1); - if (varNode != nullptr) + if (srcLclNode != nullptr) { - // Load from our varNumImp source + // Load from our local source emit->emitIns_R_R_S_S(INS_ldp, emitTypeSize(type0), emitTypeSize(type1), loReg, hiReg, - varNode->GetLclNum(), structOffset); + srcLclNode->GetLclNum(), lclOffset + structOffset); } else { @@ -1056,17 +988,18 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) nextIndex += 2; } #else // TARGET_ARM - // For a >= 4 byte structSize we will generate a ldr and str instruction each loop + // For a >= 4 byte sizes we will generate a ldr and str instruction each loop // ldr r2, [r0] // str r2, [sp, #16] while (remainingSize >= TARGET_POINTER_SIZE) { var_types type = layout->GetGCPtrType(nextIndex); - if (varNode != nullptr) + if (srcLclNode != nullptr) { - // Load from our varNumImp source - emit->emitIns_R_S(INS_ldr, emitTypeSize(type), loReg, varNode->GetLclNum(), structOffset); + // Load from our local source + emit->emitIns_R_S(INS_ldr, emitTypeSize(type), loReg, srcLclNode->GetLclNum(), + lclOffset + structOffset); } else { @@ -1088,7 +1021,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) } #endif // TARGET_ARM - // For a 12-byte structSize we will generate two load instructions + // For a 12-byte size we will generate two load instructions // ldr x2, [x0] // ldr w3, [x0, #8] // str x2, [sp, #16] @@ -1129,10 +1062,10 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode) remainingSize -= moveSize; instruction loadIns = ins_Load(type); - if (varNode != nullptr) + if (srcLclNode != nullptr) { - // Load from our varNumImp source - emit->emitIns_R_S(loadIns, attr, loReg, varNode->GetLclNum(), structOffset); + // Load from our local source + emit->emitIns_R_S(loadIns, attr, loReg, srcLclNode->GetLclNum(), lclOffset + structOffset); } else { @@ -1306,14 +1239,8 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) } else // addrNode is used { - assert(addrNode != nullptr); - // TODO-Cleanup: `Lowering::NewPutArg` marks only `LCL_VAR_ADDR` as contained nowadays, - // but we use `genConsumeAddress` as a precaution, use `genConsumeReg()` instead. - assert(!addrNode->isContained()); - // Generate code to load the address that we need into a register - genConsumeAddress(addrNode); - addrReg = addrNode->GetRegNum(); + addrReg = genConsumeReg(addrNode); // If addrReg equal to baseReg, we use the last target register as alternative baseReg. // Because the candidate mask for the internal baseReg does not include any of the target register, @@ -1327,21 +1254,40 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) ClassLayout* layout = source->AsObj()->GetLayout(); // Put on stack first - unsigned nextIndex = treeNode->gtNumRegs; - unsigned structOffset = nextIndex * TARGET_POINTER_SIZE; - int remainingSize = treeNode->GetStackByteSize(); + unsigned structOffset = treeNode->gtNumRegs * TARGET_POINTER_SIZE; + unsigned remainingSize = layout->GetSize() - structOffset; unsigned argOffsetOut = treeNode->getArgOffset(); - // remainingSize is always multiple of TARGET_POINTER_SIZE - assert(remainingSize % TARGET_POINTER_SIZE == 0); + assert((remainingSize > 0) && (roundUp(remainingSize, TARGET_POINTER_SIZE) == treeNode->GetStackByteSize())); while (remainingSize > 0) { - var_types type = layout->GetGCPtrType(nextIndex); + var_types type; + if (remainingSize >= TARGET_POINTER_SIZE) + { + type = layout->GetGCPtrType(structOffset / TARGET_POINTER_SIZE); + } + else if (remainingSize >= 4) + { + type = TYP_INT; + } + else if (remainingSize >= 2) + { + type = TYP_USHORT; + } + else + { + assert(remainingSize == 1); + type = TYP_UBYTE; + } + + emitAttr attr = emitActualTypeSize(type); + unsigned moveSize = genTypeSize(type); + instruction loadIns = ins_Load(type); if (varNode != nullptr) { - // Load from our varNumImp source - emit->emitIns_R_S(INS_ldr, emitTypeSize(type), baseReg, srcVarNum, structOffset); + // Load from our local source + emit->emitIns_R_S(loadIns, attr, baseReg, srcVarNum, structOffset); } else { @@ -1349,16 +1295,16 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) assert(baseReg != addrReg); // Load from our address expression source - emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), baseReg, addrReg, structOffset); + emit->emitIns_R_R_I(loadIns, attr, baseReg, addrReg, structOffset); } - // Emit str instruction to store the register into the outgoing argument area - emit->emitIns_S_R(INS_str, emitTypeSize(type), baseReg, varNumOut, argOffsetOut); - argOffsetOut += TARGET_POINTER_SIZE; // We stored 4-bytes of the struct - assert(argOffsetOut <= argOffsetMax); // We can't write beyond the outgoing arg area - remainingSize -= TARGET_POINTER_SIZE; // We loaded 4-bytes of the struct - structOffset += TARGET_POINTER_SIZE; - nextIndex += 1; + // Emit the instruction to store the register into the outgoing argument area + emit->emitIns_S_R(ins_Store(type), attr, baseReg, varNumOut, argOffsetOut); + argOffsetOut += moveSize; + assert(argOffsetOut <= argOffsetMax); + + remainingSize -= moveSize; + structOffset += moveSize; } // We set up the registers in order, so that we assign the last target register `baseReg` is no longer in use, @@ -1371,7 +1317,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) if (varNode != nullptr) { - // Load from our varNumImp source + // Load from our local source emit->emitIns_R_S(INS_ldr, emitTypeSize(type), targetReg, srcVarNum, structOffset); } else @@ -3929,14 +3875,9 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d case GenIntCastDesc::CHECK_INT_RANGE: { - const regNumber tempReg = cast->GetSingleTempReg(); - assert(tempReg != reg); - instGen_Set_Reg_To_Imm(EA_8BYTE, tempReg, INT32_MAX); - GetEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, reg, tempReg); - genJumpToThrowHlpBlk(EJ_gt, SCK_OVERFLOW); - instGen_Set_Reg_To_Imm(EA_8BYTE, tempReg, INT32_MIN); - GetEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, reg, tempReg); - genJumpToThrowHlpBlk(EJ_lt, SCK_OVERFLOW); + // Emit "if ((long)(int)x != x) goto OVERFLOW" + GetEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, reg, reg, INS_OPTS_SXTW); + genJumpToThrowHlpBlk(EJ_ne, SCK_OVERFLOW); } break; #endif @@ -4485,6 +4426,16 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) } else { +#ifdef TARGET_ARM64 + // Handle LEA with "contained" BFIZ + if (index->isContained() && index->OperIs(GT_BFIZ)) + { + assert(scale == 0); + scale = (DWORD)index->gtGetOp2()->AsIntConCommon()->IconValue(); + index = index->gtGetOp1()->gtGetOp1(); + } +#endif + // Then compute target reg from [base + index*scale] genScaledAdd(size, lea->GetRegNum(), memBase->GetRegNum(), index->GetRegNum(), scale); } @@ -4706,7 +4657,7 @@ void CodeGen::genPushCalleeSavedRegisters() // |-----------------------| // |Callee saved registers | // not including FP/LR; multiple of 8 bytes // |-----------------------| - // | MonitorAcquired | + // | MonitorAcquired | // 8 bytes; for synchronized methods // |-----------------------| // | PSP slot | // 8 bytes (omitted in NativeAOT ABI) // |-----------------------| @@ -4739,7 +4690,7 @@ void CodeGen::genPushCalleeSavedRegisters() // |-----------------------| // |Callee saved registers | // not including FP/LR; multiple of 8 bytes // |-----------------------| - // | MonitorAcquired | + // | MonitorAcquired | // 8 bytes; for synchronized methods // |-----------------------| // | PSP slot | // 8 bytes (omitted in NativeAOT ABI) // |-----------------------| diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index ed16b9a9fa498..d158a56211698 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -137,6 +137,7 @@ CodeGen::CodeGen(Compiler* theCompiler) : CodeGenInterface(theCompiler) #ifdef TARGET_ARM64 genSaveFpLrWithAllCalleeSavedRegisters = false; + genForceFuncletFrameType5 = false; #endif // TARGET_ARM64 } @@ -6581,35 +6582,6 @@ bool Compiler::IsHfa(CORINFO_CLASS_HANDLE hClass) return varTypeIsValidHfaType(GetHfaType(hClass)); } -bool Compiler::IsHfa(GenTree* tree) -{ - if (GlobalJitOptions::compFeatureHfa) - { - return IsHfa(gtGetStructHandleIfPresent(tree)); - } - else - { - return false; - } -} - -var_types Compiler::GetHfaType(GenTree* tree) -{ - if (GlobalJitOptions::compFeatureHfa) - { - return GetHfaType(gtGetStructHandleIfPresent(tree)); - } - else - { - return TYP_UNDEF; - } -} - -unsigned Compiler::GetHfaCount(GenTree* tree) -{ - return GetHfaCount(gtGetStructHandle(tree)); -} - var_types Compiler::GetHfaType(CORINFO_CLASS_HANDLE hClass) { if (GlobalJitOptions::compFeatureHfa) diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 6a44f1db324de..b9026bfedd6f4 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -753,24 +753,27 @@ void CodeGen::genCodeForBBlist() break; case BBJ_ALWAYS: - inst_JMP(EJ_jmp, block->bbJumpDest +#ifdef TARGET_XARCH + { + // If a block was selected to place an alignment instruction because it ended + // with a jump, do not remove jumps from such blocks. + // Do not remove a jump between hot and cold regions. + bool isRemovableJmpCandidate = + !block->hasAlign() && !compiler->fgInDifferentRegions(block, block->bbJumpDest); + #ifdef TARGET_AMD64 - // AMD64 requires an instruction after a call instruction for unwinding - // inside an EH region so if the last instruction generated was a call instruction - // do not allow this jump to be marked for possible later removal. - // - // If a block was selected to place an alignment instruction because it ended - // with a jump, do not remove jumps from such blocks. - , - /* isRemovableJmpCandidate */ !GetEmitter()->emitIsLastInsCall() && !block->hasAlign() + // AMD64 requires an instruction after a call instruction for unwinding + // inside an EH region so if the last instruction generated was a call instruction + // do not allow this jump to be marked for possible later removal. + isRemovableJmpCandidate = isRemovableJmpCandidate && !GetEmitter()->emitIsLastInsCall(); +#endif // TARGET_AMD64 + + inst_JMP(EJ_jmp, block->bbJumpDest, isRemovableJmpCandidate); + } #else -#ifdef TARGET_XARCH - , - /* isRemovableJmpCandidate */ !block->hasAlign() -#endif + inst_JMP(EJ_jmp, block->bbJumpDest); +#endif // TARGET_XARCH -#endif - ); FALLTHROUGH; case BBJ_COND: @@ -1762,21 +1765,21 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode, regNumber sizeReg) { // The putArgNode children are always contained. We should not consume any registers. - assert(putArgNode->gtGetOp1()->isContained()); + assert(putArgNode->Data()->isContained()); - // Get the source address. - GenTree* src = putArgNode->gtGetOp1(); + // Get the source. + GenTree* src = putArgNode->Data(); + regNumber srcAddrReg = REG_NA; assert(varTypeIsStruct(src)); - assert((src->gtOper == GT_OBJ) || ((src->gtOper == GT_IND && varTypeIsSIMD(src)))); - GenTree* srcAddr = src->gtGetOp1(); + assert(src->OperIs(GT_OBJ) || src->OperIsLocalRead() || (src->OperIs(GT_IND) && varTypeIsSIMD(src))); assert(dstReg != REG_NA); assert(srcReg != REG_NA); - // Consume the registers only if they are not contained or set to REG_NA. - if (srcAddr->GetRegNum() != REG_NA) + // Consume the register for the source address if needed. + if (src->OperIsIndir()) { - genConsumeReg(srcAddr); + srcAddrReg = genConsumeReg(src->AsIndir()->Addr()); } // If the op1 is already in the dstReg - nothing to do. @@ -1798,22 +1801,17 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode, } #endif // !TARGET_X86 - if (srcAddr->OperIsLocalAddr()) + if (srcAddrReg != REG_NA) { - // The OperLocalAddr is always contained. - assert(srcAddr->isContained()); - const GenTreeLclVarCommon* lclNode = srcAddr->AsLclVarCommon(); - - // Generate LEA instruction to load the LclVar address in RSI. - // Source is known to be on the stack. Use EA_PTRSIZE. - unsigned int offset = lclNode->GetLclOffs(); - GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, srcReg, lclNode->GetLclNum(), offset); + // Source is not known to be on the stack. Use EA_BYREF. + GetEmitter()->emitIns_Mov(INS_mov, EA_BYREF, srcReg, srcAddrReg, /* canSkip */ true); } else { - assert(srcAddr->GetRegNum() != REG_NA); - // Source is not known to be on the stack. Use EA_BYREF. - GetEmitter()->emitIns_Mov(INS_mov, EA_BYREF, srcReg, srcAddr->GetRegNum(), /* canSkip */ true); + // Generate LEA instruction to load the LclVar address in RSI. + // Source is known to be on the stack. Use EA_PTRSIZE. + GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, srcReg, src->AsLclVarCommon()->GetLclNum(), + src->AsLclVarCommon()->GetLclOffs()); } if (sizeReg != REG_NA) diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 67d64db8c6a82..7f85403db4017 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -1655,6 +1655,18 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ +//------------------------------------------------------------------------ +// inst_JMP: Generate a jump instruction. +// +void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock) +{ +#if !FEATURE_FIXED_OUT_ARGS + assert((tgtBlock->bbTgtStkDepth * sizeof(int) == genStackLevel) || isFramePointerUsed()); +#endif // !FEATURE_FIXED_OUT_ARGS + + GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock); +} + BasicBlock* CodeGen::genCallFinally(BasicBlock* block) { // Generate a call to the finally, like this: diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 039d4c1118522..ca050dcf49ff9 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -442,7 +442,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, } else { - GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm DEBUGARG(gtFlags)); + GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm DEBUGARG(targetHandle) DEBUGARG(gtFlags)); } } regSet.verifyRegUsed(reg); @@ -462,8 +462,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre { // relocatable values tend to come down as a CNS_INT of native int type // so the line between these two opcodes is kind of blurry - GenTreeIntConCommon* con = tree->AsIntConCommon(); - ssize_t cnsVal = con->IconValue(); + GenTreeIntCon* con = tree->AsIntCon(); + ssize_t cnsVal = con->IconValue(); emitAttr attr = emitActualTypeSize(targetType); // Currently this cannot be done for all handles due to @@ -482,7 +482,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre attr = EA_SET_FLG(attr, EA_BYREF_FLG); } - instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal, INS_FLAGS_DONT_CARE DEBUGARG(0) DEBUGARG(tree->gtFlags)); + instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal, + INS_FLAGS_DONT_CARE DEBUGARG(con->gtTargetHandle) DEBUGARG(con->gtFlags)); regSet.verifyRegUsed(targetReg); } break; @@ -516,22 +517,28 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre if (vecCon->IsAllBitsSet()) { + if ((attr != EA_32BYTE) || compiler->compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { #if defined(FEATURE_SIMD) - emit->emitIns_SIMD_R_R_R(INS_pcmpeqd, attr, targetReg, targetReg, targetReg); + emit->emitIns_SIMD_R_R_R(INS_pcmpeqd, attr, targetReg, targetReg, targetReg); #else - emit->emitIns_R_R(INS_pcmpeqd, attr, targetReg, targetReg); + emit->emitIns_R_R(INS_pcmpeqd, attr, targetReg, targetReg); #endif // FEATURE_SIMD - break; + break; + } } if (vecCon->IsZero()) { + if ((attr != EA_32BYTE) || compiler->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { #if defined(FEATURE_SIMD) - emit->emitIns_SIMD_R_R_R(INS_xorps, attr, targetReg, targetReg, targetReg); + emit->emitIns_SIMD_R_R_R(INS_xorps, attr, targetReg, targetReg, targetReg); #else - emit->emitIns_R_R(INS_xorps, attr, targetReg, targetReg); + emit->emitIns_R_R(INS_xorps, attr, targetReg, targetReg); #endif // FEATURE_SIMD - break; + break; + } } switch (tree->TypeGet()) @@ -3052,21 +3059,19 @@ void CodeGen::genCodeForInitBlkHelper(GenTreeBlk* initBlkNode) #ifdef FEATURE_PUT_STRUCT_ARG_STK // Generate code for a load from some address + offset -// baseNode: tree node which can be either a local address or arbitrary node -// offset: distance from the baseNode from which to load -void CodeGen::genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* baseNode, unsigned offset) +// base: tree node which can be either a local or an indir +// offset: distance from the "base" location from which to load +// +void CodeGen::genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset) { - emitter* emit = GetEmitter(); - - if (baseNode->OperIsLocalAddr()) + if (base->OperIsLocalRead()) { - const GenTreeLclVarCommon* lclVar = baseNode->AsLclVarCommon(); - offset += lclVar->GetLclOffs(); - emit->emitIns_R_S(ins, size, dst, lclVar->GetLclNum(), offset); + GetEmitter()->emitIns_R_S(ins, size, dst, base->AsLclVarCommon()->GetLclNum(), + offset + base->AsLclVarCommon()->GetLclOffs()); } else { - emit->emitIns_R_AR(ins, size, dst, baseNode->GetRegNum(), offset); + GetEmitter()->emitIns_R_AR(ins, size, dst, base->AsIndir()->Addr()->GetRegNum(), offset); } } #endif // FEATURE_PUT_STRUCT_ARG_STK @@ -3337,7 +3342,7 @@ void CodeGen::genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode) // Arguments: // size - The size of bytes remaining to be moved // longTmpReg - The tmp register to be used for the long value -// srcAddr - The address of the source struct +// src - The source struct node (LCL/OBJ) // offset - The current offset being copied // // Return Value: @@ -3349,7 +3354,7 @@ void CodeGen::genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode) // On x86, longTmpReg must be an xmm reg; on x64 it must be an integer register. // This is checked by genStoreRegToStackArg. // -unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* srcAddr, unsigned offset) +unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* src, unsigned offset) { #ifdef TARGET_X86 instruction longMovIns = INS_movq; @@ -3358,7 +3363,7 @@ unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* #endif // !TARGET_X86 if ((size & 8) != 0) { - genCodeForLoadOffset(longMovIns, EA_8BYTE, longTmpReg, srcAddr, offset); + genCodeForLoadOffset(longMovIns, EA_8BYTE, longTmpReg, src, offset); genStoreRegToStackArg(TYP_LONG, longTmpReg, offset); return 8; } @@ -3371,7 +3376,7 @@ unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* // Arguments: // size - The size of bytes remaining to be moved // intTmpReg - The tmp register to be used for the long value -// srcAddr - The address of the source struct +// src - The source struct node (LCL/OBJ) // offset - The current offset being copied // // Return Value: @@ -3383,11 +3388,11 @@ unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* // intTmpReg must be an integer register. // This is checked by genStoreRegToStackArg. // -unsigned CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset) +unsigned CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* src, unsigned offset) { if ((size & 4) != 0) { - genCodeForLoadOffset(INS_mov, EA_4BYTE, intTmpReg, srcAddr, offset); + genCodeForLoadOffset(INS_mov, EA_4BYTE, intTmpReg, src, offset); genStoreRegToStackArg(TYP_INT, intTmpReg, offset); return 4; } @@ -3400,7 +3405,7 @@ unsigned CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* // Arguments: // size - The size of bytes remaining to be moved // intTmpReg - The tmp register to be used for the long value -// srcAddr - The address of the source struct +// src - The source struct node (LCL/OBJ) // offset - The current offset being copied // // Return Value: @@ -3412,11 +3417,11 @@ unsigned CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* // intTmpReg must be an integer register. // This is checked by genStoreRegToStackArg. // -unsigned CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset) +unsigned CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* src, unsigned offset) { if ((size & 2) != 0) { - genCodeForLoadOffset(INS_mov, EA_2BYTE, intTmpReg, srcAddr, offset); + genCodeForLoadOffset(INS_mov, EA_2BYTE, intTmpReg, src, offset); genStoreRegToStackArg(TYP_SHORT, intTmpReg, offset); return 2; } @@ -3429,7 +3434,7 @@ unsigned CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* // Arguments: // size - The size of bytes remaining to be moved // intTmpReg - The tmp register to be used for the long value -// srcAddr - The address of the source struct +// src - The source struct node (LCL/OBJ) // offset - The current offset being copied // // Return Value: @@ -3441,11 +3446,11 @@ unsigned CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* // intTmpReg must be an integer register. // This is checked by genStoreRegToStackArg. // -unsigned CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset) +unsigned CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree* src, unsigned offset) { if ((size & 1) != 0) { - genCodeForLoadOffset(INS_mov, EA_1BYTE, intTmpReg, srcAddr, offset); + genCodeForLoadOffset(INS_mov, EA_1BYTE, intTmpReg, src, offset); genStoreRegToStackArg(TYP_BYTE, intTmpReg, offset); return 1; } @@ -3469,37 +3474,36 @@ unsigned CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree* // void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) { - GenTree* src = putArgNode->AsOp()->gtOp1; - // We will never call this method for SIMD types, which are stored directly - // in genPutStructArgStk(). - assert(src->isContained() && src->OperIs(GT_OBJ) && src->TypeIs(TYP_STRUCT)); - assert(!src->AsObj()->GetLayout()->HasGCPtr()); + GenTree* src = putArgNode->Data(); + // We will never call this method for SIMD types, which are stored directly in genPutStructArgStk(). + assert(src->isContained() && src->TypeIs(TYP_STRUCT) && (src->OperIs(GT_OBJ) || src->OperIsLocalRead())); + #ifdef TARGET_X86 assert(!m_pushStkArg); #endif - unsigned size = putArgNode->GetStackByteSize(); -#ifdef TARGET_X86 - assert((XMM_REGSIZE_BYTES <= size) && (size <= CPBLK_UNROLL_LIMIT)); -#else // !TARGET_X86 - assert(size <= CPBLK_UNROLL_LIMIT); -#endif // !TARGET_X86 - - if (src->AsOp()->gtOp1->isUsedFromReg()) + if (src->OperIs(GT_OBJ)) { - genConsumeReg(src->AsOp()->gtOp1); + genConsumeReg(src->AsObj()->Addr()); } + unsigned loadSize = putArgNode->GetArgLoadSize(); + assert(!src->GetLayout(compiler)->HasGCPtr() && (loadSize <= CPBLK_UNROLL_LIMIT)); + unsigned offset = 0; regNumber xmmTmpReg = REG_NA; regNumber intTmpReg = REG_NA; regNumber longTmpReg = REG_NA; - if (size >= XMM_REGSIZE_BYTES) +#ifdef TARGET_X86 + if (loadSize >= 8) +#else + if (loadSize >= XMM_REGSIZE_BYTES) +#endif { xmmTmpReg = putArgNode->GetSingleTempReg(RBM_ALLFLOAT); } - if ((size % XMM_REGSIZE_BYTES) != 0) + if ((loadSize % XMM_REGSIZE_BYTES) != 0) { intTmpReg = putArgNode->GetSingleTempReg(RBM_ALLINT); } @@ -3511,7 +3515,7 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) #endif // Let's use SSE2 to be able to do 16 byte at a time with loads and stores. - size_t slots = size / XMM_REGSIZE_BYTES; + size_t slots = loadSize / XMM_REGSIZE_BYTES; while (slots-- > 0) { // TODO: In the below code the load and store instructions are for 16 bytes, but the @@ -3519,7 +3523,7 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) // this probably needs to be changed. // Load - genCodeForLoadOffset(INS_movdqu, EA_8BYTE, xmmTmpReg, src->gtGetOp1(), offset); + genCodeForLoadOffset(INS_movdqu, EA_8BYTE, xmmTmpReg, src, offset); // Store genStoreRegToStackArg(TYP_STRUCT, xmmTmpReg, offset); @@ -3527,13 +3531,13 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) } // Fill the remainder (15 bytes or less) if there's one. - if ((size % XMM_REGSIZE_BYTES) != 0) + if ((loadSize % XMM_REGSIZE_BYTES) != 0) { - offset += genMove8IfNeeded(size, longTmpReg, src->AsOp()->gtOp1, offset); - offset += genMove4IfNeeded(size, intTmpReg, src->AsOp()->gtOp1, offset); - offset += genMove2IfNeeded(size, intTmpReg, src->AsOp()->gtOp1, offset); - offset += genMove1IfNeeded(size, intTmpReg, src->AsOp()->gtOp1, offset); - assert(offset == size); + offset += genMove8IfNeeded(loadSize, longTmpReg, src, offset); + offset += genMove4IfNeeded(loadSize, intTmpReg, src, offset); + offset += genMove2IfNeeded(loadSize, intTmpReg, src, offset); + offset += genMove1IfNeeded(loadSize, intTmpReg, src, offset); + assert(offset == loadSize); } } @@ -3549,8 +3553,7 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode) void CodeGen::genStructPutArgRepMovs(GenTreePutArgStk* putArgNode) { GenTree* src = putArgNode->gtGetOp1(); - assert(src->TypeGet() == TYP_STRUCT); - assert(!src->AsObj()->GetLayout()->HasGCPtr()); + assert(src->TypeIs(TYP_STRUCT) && !src->GetLayout(compiler)->HasGCPtr()); // Make sure we got the arguments of the cpblk operation in the right registers, and that // 'src' is contained as expected. @@ -3569,8 +3572,9 @@ void CodeGen::genStructPutArgRepMovs(GenTreePutArgStk* putArgNode) // putArgNode - the PutArgStk tree. // // Notes: -// Used only on x86, in two cases: +// Used (only) on x86 for: // - Structs 4, 8, or 12 bytes in size (less than XMM_REGSIZE_BYTES, multiple of TARGET_POINTER_SIZE). +// - Local structs less than 16 bytes in size (it is ok to load "too much" from our stack frame). // - Structs that contain GC pointers - they are guaranteed to be sized correctly by the VM. // void CodeGen::genStructPutArgPush(GenTreePutArgStk* putArgNode) @@ -3583,42 +3587,37 @@ void CodeGen::genStructPutArgPush(GenTreePutArgStk* putArgNode) // future. assert(m_pushStkArg); - GenTree* src = putArgNode->Data(); - GenTree* srcAddr = putArgNode->Data()->AsObj()->Addr(); - - regNumber srcAddrReg = srcAddr->GetRegNum(); - const bool srcAddrInReg = srcAddrReg != REG_NA; - - unsigned srcLclNum = 0; - unsigned srcLclOffset = 0; - if (srcAddrInReg) + GenTree* src = putArgNode->Data(); + regNumber srcAddrReg = REG_NA; + unsigned srcLclNum = BAD_VAR_NUM; + unsigned srcLclOffs = BAD_LCL_OFFSET; + if (src->OperIsLocalRead()) { - srcAddrReg = genConsumeReg(srcAddr); + assert(src->isContained()); + srcLclNum = src->AsLclVarCommon()->GetLclNum(); + srcLclOffs = src->AsLclVarCommon()->GetLclOffs(); } else { - assert(srcAddr->OperIsLocalAddr()); - - srcLclNum = srcAddr->AsLclVarCommon()->GetLclNum(); - srcLclOffset = srcAddr->AsLclVarCommon()->GetLclOffs(); + srcAddrReg = genConsumeReg(src->AsObj()->Addr()); } - ClassLayout* layout = src->AsObj()->GetLayout(); - const unsigned byteSize = putArgNode->GetStackByteSize(); - assert((byteSize % TARGET_POINTER_SIZE == 0) && ((byteSize < XMM_REGSIZE_BYTES) || layout->HasGCPtr())); - const unsigned numSlots = byteSize / TARGET_POINTER_SIZE; + ClassLayout* layout = src->GetLayout(compiler); + const unsigned loadSize = putArgNode->GetArgLoadSize(); + assert(((loadSize < XMM_REGSIZE_BYTES) || layout->HasGCPtr()) && ((loadSize % TARGET_POINTER_SIZE) == 0)); + const unsigned numSlots = loadSize / TARGET_POINTER_SIZE; for (int i = numSlots - 1; i >= 0; --i) { emitAttr slotAttr = emitTypeSize(layout->GetGCPtrType(i)); const unsigned byteOffset = i * TARGET_POINTER_SIZE; - if (srcAddrInReg) + if (srcAddrReg != REG_NA) { GetEmitter()->emitIns_AR_R(INS_push, slotAttr, REG_NA, srcAddrReg, byteOffset); } else { - GetEmitter()->emitIns_S(INS_push, slotAttr, srcLclNum, srcLclOffset + byteOffset); + GetEmitter()->emitIns_S(INS_push, slotAttr, srcLclNum, srcLclOffs + byteOffset); } AddStackLevel(TARGET_POINTER_SIZE); @@ -3643,19 +3642,18 @@ void CodeGen::genStructPutArgPartialRepMovs(GenTreePutArgStk* putArgNode) // They may now contain gc pointers (depending on their type; gcMarkRegPtrVal will "do the right thing"). genConsumePutStructArgStk(putArgNode, REG_RDI, REG_RSI, REG_NA); - GenTreeObj* src = putArgNode->gtGetOp1()->AsObj(); - ClassLayout* layout = src->GetLayout(); - const bool srcIsLocal = src->Addr()->OperIsLocalAddr(); - const emitAttr srcAddrAttr = srcIsLocal ? EA_PTRSIZE : EA_BYREF; + GenTree* src = putArgNode->Data(); + ClassLayout* layout = src->GetLayout(compiler); + const emitAttr srcAddrAttr = src->OperIsLocalRead() ? EA_PTRSIZE : EA_BYREF; #if DEBUG unsigned numGCSlotsCopied = 0; #endif // DEBUG assert(layout->HasGCPtr()); - const unsigned byteSize = putArgNode->GetStackByteSize(); - assert(byteSize % TARGET_POINTER_SIZE == 0); - const unsigned numSlots = byteSize / TARGET_POINTER_SIZE; + const unsigned argSize = putArgNode->GetStackByteSize(); + assert(argSize % TARGET_POINTER_SIZE == 0); + const unsigned numSlots = argSize / TARGET_POINTER_SIZE; // No need to disable GC the way COPYOBJ does. Here the refs are copied in atomic operations always. for (unsigned i = 0; i < numSlots;) @@ -4763,7 +4761,8 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree) unsigned varNum = tree->GetLclNum(); assert(varNum < compiler->lvaCount); - GetEmitter()->emitIns_R_S(ins_Load(targetType), size, targetReg, varNum, offs); + instruction loadIns = tree->DontExtend() ? INS_mov : ins_Load(targetType); + GetEmitter()->emitIns_R_S(loadIns, size, targetReg, varNum, offs); genProduceReg(tree); } @@ -5114,16 +5113,7 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) else { genConsumeAddress(addr); - instruction loadIns = ins_Load(targetType); - if (tree->DontExtend()) - { - assert(varTypeIsSmall(tree)); - // The user of this IND does not need - // the upper bits to be set, so we don't need to use longer - // INS_movzx/INS_movsx and can use INS_mov instead. - // It usually happens when the real type is a small struct. - loadIns = INS_mov; - } + instruction loadIns = tree->DontExtend() ? INS_mov : ins_Load(targetType); emit->emitInsLoadInd(loadIns, emitTypeSize(tree), tree->GetRegNum(), tree); } @@ -5524,23 +5514,17 @@ void CodeGen::genCall(GenTreeCall* call) GenTree* argNode = arg.GetEarlyNode(); if (argNode->OperIs(GT_PUTARG_STK) && (arg.GetLateNode() == nullptr)) { - GenTree* source = argNode->AsPutArgStk()->gtGetOp1(); - unsigned size = argNode->AsPutArgStk()->GetStackByteSize(); - stackArgBytes += size; + GenTree* source = argNode->AsPutArgStk()->gtGetOp1(); + unsigned argSize = argNode->AsPutArgStk()->GetStackByteSize(); + stackArgBytes += argSize; + #ifdef DEBUG - assert(size == arg.AbiInfo.ByteSize); + assert(argSize == arg.AbiInfo.ByteSize); #ifdef FEATURE_PUT_STRUCT_ARG_STK - if (!source->OperIs(GT_FIELD_LIST) && (source->TypeGet() == TYP_STRUCT)) + if (source->TypeIs(TYP_STRUCT) && !source->OperIs(GT_FIELD_LIST)) { - GenTreeObj* obj = source->AsObj(); - unsigned argBytes = roundUp(obj->GetLayout()->GetSize(), TARGET_POINTER_SIZE); -#ifdef TARGET_X86 - // If we have an OBJ, we must have created a copy if the original arg was not a - // local and was not a multiple of TARGET_POINTER_SIZE. - // Note that on x64/ux this will be handled by unrolling in genStructPutArgUnroll. - assert((argBytes == obj->GetLayout()->GetSize()) || obj->Addr()->IsLocalAddrExpr()); -#endif // TARGET_X86 - assert(arg.AbiInfo.ByteSize == argBytes); + unsigned loadSize = source->GetLayout(compiler)->GetSize(); + assert(argSize == roundUp(loadSize, TARGET_POINTER_SIZE)); } #endif // FEATURE_PUT_STRUCT_ARG_STK #endif // DEBUG @@ -6746,11 +6730,14 @@ void CodeGen::genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& d break; case GenIntCastDesc::CHECK_INT_RANGE: - GetEmitter()->emitIns_R_I(INS_cmp, EA_8BYTE, reg, INT32_MAX); - genJumpToThrowHlpBlk(EJ_jg, SCK_OVERFLOW); - GetEmitter()->emitIns_R_I(INS_cmp, EA_8BYTE, reg, INT32_MIN); - genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW); - break; + { + // Emit "if ((long)(int)x != x) goto OVERFLOW" + const regNumber regTmp = cast->GetSingleTempReg(); + GetEmitter()->emitIns_Mov(INS_movsxd, EA_8BYTE, regTmp, reg, true); + GetEmitter()->emitIns_R_R(INS_cmp, EA_8BYTE, reg, regTmp); + genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW); + } + break; #endif default: @@ -7796,11 +7783,11 @@ bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk) { case GenTreePutArgStk::Kind::RepInstr: case GenTreePutArgStk::Kind::Unroll: - assert(!source->AsObj()->GetLayout()->HasGCPtr()); + assert(!source->GetLayout(compiler)->HasGCPtr()); break; case GenTreePutArgStk::Kind::Push: - assert(source->OperIs(GT_FIELD_LIST) || source->AsObj()->GetLayout()->HasGCPtr() || + assert(source->OperIs(GT_FIELD_LIST) || source->GetLayout(compiler)->HasGCPtr() || (argSize < XMM_REGSIZE_BYTES)); break; @@ -8314,14 +8301,11 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk) assert(targetType == TYP_STRUCT); - ClassLayout* layout = source->AsObj()->GetLayout(); - switch (putArgStk->gtPutArgStkKind) { case GenTreePutArgStk::Kind::RepInstr: genStructPutArgRepMovs(putArgStk); break; - #ifndef TARGET_X86 case GenTreePutArgStk::Kind::PartialRepInstr: genStructPutArgPartialRepMovs(putArgStk); diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 2201c3a7d1e8d..460412d84597e 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -3199,10 +3199,10 @@ void Compiler::compInitOptions(JitFlags* jitFlags) opts.compProcedureSplitting = jitFlags->IsSet(JitFlags::JIT_FLAG_PROCSPLIT) || enableFakeSplitting; -#ifdef TARGET_ARM64 - // TODO-ARM64-NYI: enable hot/cold splitting +#ifdef TARGET_LOONGARCH64 + // Hot/cold splitting is not being tested on LoongArch64. opts.compProcedureSplitting = false; -#endif // TARGET_ARM64 +#endif // TARGET_LOONGARCH64 #ifdef DEBUG opts.compProcedureSplittingEH = opts.compProcedureSplitting; @@ -5199,25 +5199,41 @@ void Compiler::placeLoopAlignInstructions() { // Loop alignment is disabled for cold blocks assert((block->bbFlags & BBF_COLD) == 0); + BasicBlock* const loopTop = block->bbNext; // If jmp was not found, then block before the loop start is where align instruction will be added. + // if (bbHavingAlign == nullptr) { - bbHavingAlign = block; - JITDUMP("Marking " FMT_BB " before the loop with BBF_HAS_ALIGN for loop at " FMT_BB "\n", block->bbNum, - block->bbNext->bbNum); + // In some odd cases we may see blocks within the loop before we see the + // top block of the loop. Just bail on aligning such loops. + // + if ((block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) && (block->bbNatLoopNum == loopTop->bbNatLoopNum)) + { + loopTop->unmarkLoopAlign(this DEBUG_ARG("loop block appears before top of loop")); + } + else + { + bbHavingAlign = block; + JITDUMP("Marking " FMT_BB " before the loop with BBF_HAS_ALIGN for loop at " FMT_BB "\n", + block->bbNum, loopTop->bbNum); + } } else { JITDUMP("Marking " FMT_BB " that ends with unconditional jump with BBF_HAS_ALIGN for loop at " FMT_BB "\n", - bbHavingAlign->bbNum, block->bbNext->bbNum); + bbHavingAlign->bbNum, loopTop->bbNum); + } + + if (bbHavingAlign != nullptr) + { + bbHavingAlign->bbFlags |= BBF_HAS_ALIGN; } - bbHavingAlign->bbFlags |= BBF_HAS_ALIGN; minBlockSoFar = BB_MAX_WEIGHT; bbHavingAlign = nullptr; - currentAlignedLoopNum = block->bbNext->bbNatLoopNum; + currentAlignedLoopNum = loopTop->bbNatLoopNum; if (--loopsToProcess == 0) { @@ -6384,10 +6400,10 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, compHndBBtabCount = 0; compHndBBtabAllocCount = 0; - info.compNativeCodeSize = 0; - info.compTotalHotCodeSize = 0; - info.compTotalColdCodeSize = 0; - info.compClassProbeCount = 0; + info.compNativeCodeSize = 0; + info.compTotalHotCodeSize = 0; + info.compTotalColdCodeSize = 0; + info.compHandleHistogramProbeCount = 0; compHasBackwardJump = false; compHasBackwardJumpInHandler = false; @@ -6563,7 +6579,7 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, { // This looks like a viable inline candidate. Since // we're not actually inlining, don't report anything. - prejitResult.SetReported(); + prejitResult.SetSuccessResult(INLINE_PREJIT_SUCCESS); } } else diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b4c7eb375b4d2..b5bfdf926f212 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -477,9 +477,9 @@ class LclVarDsc unsigned char lvIsTemp : 1; // Short-lifetime compiler temp -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS unsigned char lvIsImplicitByRef : 1; // Set if the argument is an implicit byref. -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#endif // FEATURE_IMPLICIT_BYREFS #if defined(TARGET_LOONGARCH64) unsigned char lvIs4Field1 : 1; // Set if the 1st field is int or float within struct for LA-ABI64. @@ -614,6 +614,8 @@ class LclVarDsc unsigned char lvSingleDefDisqualifyReason = 'H'; #endif + unsigned char lvAllDefsAreNoGc : 1; // For pinned locals: true if all defs of this local are no-gc + #if FEATURE_MULTIREG_ARGS regNumber lvRegNumForSlot(unsigned slotNum) { @@ -1015,13 +1017,8 @@ class LclVarDsc return NO_CLASS_HANDLE; } #endif - assert(m_layout != nullptr); -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - assert(varTypeIsStruct(TypeGet()) || (lvIsImplicitByRef && (TypeGet() == TYP_BYREF))); -#else - assert(varTypeIsStruct(TypeGet())); -#endif - CORINFO_CLASS_HANDLE structHnd = m_layout->GetClassHandle(); + + CORINFO_CLASS_HANDLE structHnd = GetLayout()->GetClassHandle(); assert(structHnd != NO_CLASS_HANDLE); return structHnd; } @@ -1091,10 +1088,14 @@ class LclVarDsc return varTypeIsGC(lvType) || ((lvType == TYP_STRUCT) && m_layout->HasGCPtr()); } - // Returns the layout of a struct variable. + // Returns the layout of a struct variable or implicit byref. ClassLayout* GetLayout() const { - assert(varTypeIsStruct(lvType)); +#if FEATURE_IMPLICIT_BYREFS + assert(varTypeIsStruct(TypeGet()) || (lvIsImplicitByRef && (TypeGet() == TYP_BYREF))); +#else + assert(varTypeIsStruct(TypeGet())); +#endif return m_layout; } @@ -1242,6 +1243,16 @@ class IntegralRange assert(lowerBound <= upperBound); } + SymbolicIntegerValue GetLowerBound() + { + return m_lowerBound; + } + + SymbolicIntegerValue GetUpperBound() + { + return m_upperBound; + } + bool Contains(int64_t value) const; bool Contains(IntegralRange other) const @@ -1820,6 +1831,7 @@ class Compiler friend class MorphInitBlockHelper; friend class MorphCopyBlockHelper; friend class CallArgs; + friend class IndirectCallTransformer; #ifdef FEATURE_HW_INTRINSICS friend struct HWIntrinsicInfo; @@ -1882,11 +1894,6 @@ class Compiler // bool IsHfa(CORINFO_CLASS_HANDLE hClass); - bool IsHfa(GenTree* tree); - - var_types GetHfaType(GenTree* tree); - unsigned GetHfaCount(GenTree* tree); - var_types GetHfaType(CORINFO_CLASS_HANDLE hClass); unsigned GetHfaCount(CORINFO_CLASS_HANDLE hClass); @@ -2269,7 +2276,7 @@ class Compiler GenTree* gtNewIndOfIconHandleNode(var_types indType, size_t value, GenTreeFlags iconFlags, bool isInvariant); - GenTree* gtNewIconHandleNode(size_t value, GenTreeFlags flags, FieldSeqNode* fields = nullptr); + GenTreeIntCon* gtNewIconHandleNode(size_t value, GenTreeFlags flags, FieldSeqNode* fields = nullptr); GenTreeFlags gtTokenToIconFlags(unsigned token); @@ -3286,22 +3293,8 @@ class Compiler } #endif // TARGET_X86 - // For x64 this is 3, 5, 6, 7, >8 byte structs that are passed by reference. - // For ARM64, this is structs larger than 16 bytes that are passed by reference. - bool lvaIsImplicitByRefLocal(unsigned varNum) - { -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - LclVarDsc* varDsc = lvaGetDesc(varNum); - if (varDsc->lvIsImplicitByRef) - { - assert(varDsc->lvIsParam); - - assert(varTypeIsStruct(varDsc) || (varDsc->lvType == TYP_BYREF)); - return true; - } -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - return false; - } + bool lvaIsImplicitByRefLocal(unsigned lclNum) const; + bool lvaIsLocalImplicitlyAccessedByRef(unsigned lclNum) const; // Returns true if this local var is a multireg struct bool lvaIsMultiregStruct(LclVarDsc* varDsc, bool isVararg); @@ -3557,6 +3550,18 @@ class Compiler bool isExplicitTailCall, IL_OFFSET ilOffset = BAD_IL_OFFSET); + bool impConsiderCallProbe(GenTreeCall* call, IL_OFFSET ilOffset); + + enum class GDVProbeType + { + None, + ClassProfile, + MethodProfile, + MethodAndClassProfile, + }; + + GDVProbeType compClassifyGDVProbeType(GenTreeCall* call); + //========================================================================= // PROTECTED //========================================================================= @@ -3852,10 +3857,7 @@ class Compiler var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoType* simdBaseJitType = nullptr); - GenTree* impNormStructVal(GenTree* structVal, - CORINFO_CLASS_HANDLE structHnd, - unsigned curLevel, - bool forceNormalization = false); + GenTree* impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel); GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool* pRuntimeLookup = nullptr, @@ -5374,13 +5376,6 @@ class Compiler void* pCallBackData = nullptr, bool computeStack = false); - // An fgWalkPreFn that looks for expressions that have inline throws in - // minopts mode. Basically it looks for tress with gtOverflowEx() or - // GTF_IND_RNGCHK. It returns WALK_ABORT if one is found. It - // returns WALK_SKIP_SUBTREES if GTF_EXCEPT is not set (assumes flags - // properly propagated to parent trees). It returns WALK_CONTINUE - // otherwise. - static fgWalkResult fgChkThrowCB(GenTree** pTree, Compiler::fgWalkData* data); static fgWalkResult fgChkLocAllocCB(GenTree** pTree, Compiler::fgWalkData* data); static fgWalkResult fgChkQmarkCB(GenTree** pTree, Compiler::fgWalkData* data); @@ -5445,7 +5440,7 @@ class Compiler bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, weight_t* weight); Instrumentor* fgCountInstrumentor; - Instrumentor* fgClassInstrumentor; + Instrumentor* fgHistogramInstrumentor; PhaseStatus fgPrepareToInstrumentMethod(); PhaseStatus fgInstrumentMethod(); @@ -5453,12 +5448,6 @@ class Compiler void fgIncorporateBlockCounts(); void fgIncorporateEdgeCounts(); - CORINFO_CLASS_HANDLE getRandomClass(ICorJitInfo::PgoInstrumentationSchema* schema, - UINT32 countSchemaItems, - BYTE* pInstrumentationData, - int32_t ilOffset, - CLRRandom* random); - public: const char* fgPgoFailReason; bool fgPgoDisabled; @@ -5649,7 +5638,10 @@ class Compiler void fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg); GenTree* fgMorphLocal(GenTreeLclVarCommon* lclNode); +#ifdef TARGET_X86 GenTree* fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode); +#endif // TARGET_X86 + GenTree* fgMorphExpandImplicitByRefArg(GenTreeLclVarCommon* lclNode); GenTree* fgMorphLocalVar(GenTree* tree, bool forceRemorph); public: @@ -5694,6 +5686,7 @@ class Compiler Statement* paramAssignmentInsertionPoint); GenTree* fgMorphCall(GenTreeCall* call); GenTree* fgExpandVirtualVtableCallTarget(GenTreeCall* call); + void fgMorphCallInline(GenTreeCall* call, InlineResult* result); void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result, InlineContext** createdContext); #if DEBUG @@ -5715,8 +5708,10 @@ class Compiler GenTree* fgMorphForRegisterFP(GenTree* tree); GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr); GenTree* fgOptimizeCast(GenTreeCast* cast); + GenTree* fgOptimizeCastOnAssignment(GenTreeOp* asg); GenTree* fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp); GenTree* fgOptimizeRelationalComparisonWithConst(GenTreeOp* cmp); + GenTree* fgOptimizeRelationalComparisonWithFullRangeConst(GenTreeOp* cmp); #ifdef FEATURE_HW_INTRINSICS GenTree* fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node); #endif @@ -5863,10 +5858,6 @@ class Compiler // promoted, create new promoted struct temps. void fgRetypeImplicitByRefArgs(); - // Rewrite appearances of implicit byrefs (manifest the implied additional level of indirection). - bool fgMorphImplicitByRefArgs(GenTree* tree); - GenTree* fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr); - // Clear up annotations for any struct promotion temps created for implicit byrefs. void fgMarkDemotedImplicitByRefArgs(); @@ -5901,6 +5892,8 @@ class Compiler bool gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper = nullptr); bool gtIsActiveCSE_Candidate(GenTree* tree); + ExceptionSetFlags gtCollectExceptions(GenTree* tree); + bool fgIsBigOffset(size_t offset); bool fgNeedReturnSpillTemp(); @@ -5936,13 +5929,11 @@ class Compiler VNSet* m_pHoistedInCurLoop; public: - // Value numbers of expressions that have been hoisted in parent loops in the loop nest. - VNSet m_hoistedInParentLoops; - // Value numbers of expressions that have been hoisted in the current (or most recent) loop in the nest. // Previous decisions on loop-invariance of value numbers in the current loop. VNSet m_curLoopVnInvariantCache; + // Get the VN cache for current loop VNSet* GetHoistedInCurLoop(Compiler* comp) { if (m_pHoistedInCurLoop == nullptr) @@ -5952,35 +5943,35 @@ class Compiler return m_pHoistedInCurLoop; } - VNSet* ExtractHoistedInCurLoop() + // Return the so far collected VNs in cache for current loop and reset it. + void ResetHoistedInCurLoop() { - VNSet* res = m_pHoistedInCurLoop; m_pHoistedInCurLoop = nullptr; - return res; + JITDUMP("Resetting m_pHoistedInCurLoop\n"); } LoopHoistContext(Compiler* comp) - : m_pHoistedInCurLoop(nullptr) - , m_hoistedInParentLoops(comp->getAllocatorLoopHoist()) - , m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist()) + : m_pHoistedInCurLoop(nullptr), m_curLoopVnInvariantCache(comp->getAllocatorLoopHoist()) { } }; - // Do hoisting for loop "lnum" (an index into the optLoopTable), and all loops nested within it. - // Tracks the expressions that have been hoisted by containing loops by temporarily recording their - // value numbers in "m_hoistedInParentLoops". This set is not modified by the call. + // Do hoisting of all loops nested within loop "lnum" (an index into the optLoopTable), followed + // by the loop "lnum" itself. + // + // "m_pHoistedInCurLoop" helps a lot in eliminating duplicate expressions getting hoisted + // and reducing the count of total expressions hoisted out of loop. When calculating the + // profitability, we compare this with number of registers and hence, lower the number of expressions + // getting hoisted, better chances that they will get enregistered and CSE considering them. + // void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt); // Do hoisting for a particular loop ("lnum" is an index into the optLoopTable.) - // Assumes that expressions have been hoisted in containing loops if their value numbers are in - // "m_hoistedInParentLoops". - // - void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt); + // Returns the new preheaders created. + void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt, BasicBlockList* existingPreHeaders); // Hoist all expressions in "blocks" that are invariant in loop "loopNum" (an index into the optLoopTable) - // outside of that loop. Exempt expressions whose value number is in "m_hoistedInParentLoops"; add VN's of hoisted - // expressions to "hoistInLoop". + // outside of that loop. void optHoistLoopBlocks(unsigned loopNum, ArrayStack* blocks, LoopHoistContext* hoistContext); // Return true if the tree looks profitable to hoist out of loop 'lnum'. @@ -6357,12 +6348,23 @@ class Compiler // unshared with any other loop. Returns "true" iff the flowgraph has been modified bool optCanonicalizeLoop(unsigned char loopInd); + enum class LoopCanonicalizationOption + { + Outer, + Current + }; + + bool optCanonicalizeLoopCore(unsigned char loopInd, LoopCanonicalizationOption option); + // Requires "l1" to be a valid loop table index, and not "BasicBlock::NOT_IN_LOOP". // Requires "l2" to be a valid loop table index, or else "BasicBlock::NOT_IN_LOOP". // Returns true iff "l2" is not NOT_IN_LOOP, and "l1" contains "l2". // A loop contains itself. bool optLoopContains(unsigned l1, unsigned l2) const; + // Returns the lpEntry for given preheader block of a loop + BasicBlock* optLoopEntry(BasicBlock* preHeader); + // Updates the loop table by changing loop "loopInd", whose head is required // to be "from", to be "to". Also performs this transformation for any // loop nested in "loopInd" that shares the same head as "loopInd". @@ -6815,13 +6817,21 @@ class Compiler optMethodFlags |= OMF_HAS_GUARDEDDEVIRT; } + void pickGDV(GenTreeCall* call, + IL_OFFSET ilOffset, + bool isInterface, + CORINFO_CLASS_HANDLE* classGuess, + CORINFO_METHOD_HANDLE* methodGuess, + unsigned* likelihood); + void considerGuardedDevirtualization(GenTreeCall* call, IL_OFFSET ilOffset, bool isInterface, CORINFO_METHOD_HANDLE baseMethod, CORINFO_CLASS_HANDLE baseClass, - CORINFO_CONTEXT_HANDLE* pContextHandle DEBUGARG(CORINFO_CLASS_HANDLE objClass) - DEBUGARG(const char* objClassName)); + CORINFO_CONTEXT_HANDLE* pContextHandle); + + bool isCompatibleMethodGDV(GenTreeCall* call, CORINFO_METHOD_HANDLE gdvTarget); void addGuardedDevirtualizationCandidate(GenTreeCall* call, CORINFO_METHOD_HANDLE methodHandle, @@ -7264,6 +7274,7 @@ class Compiler GenTree* optConstantAssertionProp(AssertionDsc* curAssertion, GenTreeLclVarCommon* tree, Statement* stmt DEBUGARG(AssertionIndex index)); + bool optIsProfitableToSubstitute(GenTreeLclVarCommon* lcl, BasicBlock* lclBlock, GenTree* value); bool optZeroObjAssertionProp(GenTree* tree, ASSERT_VALARG_TP assertions); // Assertion propagation functions. @@ -7649,7 +7660,7 @@ class Compiler // ICorJitInfo wrappers - void eeAllocMem(AllocMemArgs* args); + void eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSectionAlignment); void eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize); @@ -8006,10 +8017,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode); void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode); -#ifdef DEBUG - void fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode); -#endif // DEBUG - #endif // TARGET_AMD64 || (TARGET_X86 && FEATURE_EH_FUNCLETS) UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func); @@ -9556,7 +9563,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned genCPU; // What CPU are we running on // Number of class profile probes in this method - unsigned compClassProbeCount; + unsigned compHandleHistogramProbeCount; } info; diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 2fe7c10574c6b..f6fa0e2d946b6 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -902,9 +902,8 @@ inline GenTree* Compiler::gtNewLargeOperNode(genTreeOps oper, var_types type, Ge * that may need to be fixed up). */ -inline GenTree* Compiler::gtNewIconHandleNode(size_t value, GenTreeFlags flags, FieldSeqNode* fields) +inline GenTreeIntCon* Compiler::gtNewIconHandleNode(size_t value, GenTreeFlags flags, FieldSeqNode* fields) { - GenTree* node; assert((flags & (GTF_ICON_HDL_MASK | GTF_ICON_FIELD_OFF)) != 0); // Interpret "fields == NULL" as "not a field." @@ -913,6 +912,7 @@ inline GenTree* Compiler::gtNewIconHandleNode(size_t value, GenTreeFlags flags, fields = FieldSeqStore::NotAField(); } + GenTreeIntCon* node; #if defined(LATE_DISASM) node = new (this, LargeOpOpcode()) GenTreeIntCon(TYP_I_IMPL, value, fields DEBUGARG(/*largeNode*/ true)); #else @@ -1123,19 +1123,16 @@ inline GenTreeField* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDL LclVarDsc* varDsc = lvaGetDesc(obj->AsUnOp()->gtOp1->AsLclVarCommon()); varDsc->lvFieldAccessed = 1; -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - // These structs are passed by reference and can easily become global - // references if those references are exposed. We clear out - // address-exposure information for these parameters when they are - // converted into references in fgRetypeImplicitByRefArgs() so we do - // not have the necessary information in morph to know if these - // indirections are actually global references, so we have to be - // conservative here. - if (varDsc->lvIsParam) + + if (lvaIsImplicitByRefLocal(lvaGetLclNum(varDsc))) { + // These structs are passed by reference and can easily become global references if those + // references are exposed. We clear out address-exposure information for these parameters + // when they are converted into references in fgRetypeImplicitByRefArgs() so we do not have + // the necessary information in morph to know if these indirections are actually global + // references, so we have to be conservative here. fieldNode->gtFlags |= GTF_GLOB_REF; } -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) } else { @@ -1370,6 +1367,7 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate) { case GT_CNS_INT: AsIntCon()->gtFieldSeq = FieldSeqStore::NotAField(); + INDEBUG(AsIntCon()->gtTargetHandle = 0); break; #if defined(TARGET_ARM) case GT_MUL_LONG: @@ -1879,10 +1877,10 @@ inline void LclVarDsc::incRefCnts(weight_t weight, Compiler* comp, RefCountState bool doubleWeight = lvIsTemp; -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS // and, for the time being, implicit byref params doubleWeight |= lvIsImplicitByRef; -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#endif // FEATURE_IMPLICIT_BYREFS if (doubleWeight && (weight * 2 > weight)) { diff --git a/src/coreclr/jit/decomposelongs.cpp b/src/coreclr/jit/decomposelongs.cpp index 781afe9dfbf32..d3be8577df4b4 100644 --- a/src/coreclr/jit/decomposelongs.cpp +++ b/src/coreclr/jit/decomposelongs.cpp @@ -931,7 +931,6 @@ GenTree* DecomposeLongs::DecomposeNeg(LIR::Use& use) Range().InsertAfter(loResult, zero, hiAdjust, hiResult); loResult->gtFlags |= GTF_SET_FLAGS; - hiAdjust->gtFlags |= GTF_USE_FLAGS; #elif defined(TARGET_ARM) @@ -942,7 +941,6 @@ GenTree* DecomposeLongs::DecomposeNeg(LIR::Use& use) Range().InsertAfter(loResult, hiResult); loResult->gtFlags |= GTF_SET_FLAGS; - hiResult->gtFlags |= GTF_USE_FLAGS; #endif @@ -997,7 +995,6 @@ GenTree* DecomposeLongs::DecomposeArith(LIR::Use& use) if ((oper == GT_ADD) || (oper == GT_SUB)) { loResult->gtFlags |= GTF_SET_FLAGS; - hiResult->gtFlags |= GTF_USE_FLAGS; if ((loResult->gtFlags & GTF_OVERFLOW) != 0) { diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index f8c437e326694..d09bffa0a5e9a 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -1122,34 +1122,64 @@ void Compiler::eeDispLineInfos() * (e.g., host AMD64, target ARM64), then VM will get confused anyway. */ -void Compiler::eeAllocMem(AllocMemArgs* args) +void Compiler::eeAllocMem(AllocMemArgs* args, const UNATIVE_OFFSET roDataSectionAlignment) { #ifdef DEBUG - const UNATIVE_OFFSET hotSizeRequest = args->hotCodeSize; - const UNATIVE_OFFSET coldSizeRequest = args->coldCodeSize; - // Fake splitting implementation: place hot/cold code in contiguous section - if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0)) + // Fake splitting implementation: place hot/cold code in contiguous section. + UNATIVE_OFFSET coldCodeOffset = 0; + if (JitConfig.JitFakeProcedureSplitting() && (args->coldCodeSize > 0)) { - args->hotCodeSize = hotSizeRequest + coldSizeRequest; + coldCodeOffset = args->hotCodeSize; + assert(coldCodeOffset > 0); + args->hotCodeSize += args->coldCodeSize; args->coldCodeSize = 0; } -#endif + +#endif // DEBUG + +#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + + // For arm64/LoongArch64, we want to allocate JIT data always adjacent to code similar to what native compiler does. + // This way allows us to use a single `ldr` to access such data like float constant/jmp table. + // For LoongArch64 using `pcaddi + ld` to access such data. + + UNATIVE_OFFSET roDataAlignmentDelta = 0; + if (args->roDataSize > 0) + { + roDataAlignmentDelta = AlignmentPad(args->hotCodeSize, roDataSectionAlignment); + } + + const UNATIVE_OFFSET roDataOffset = args->hotCodeSize + roDataAlignmentDelta; + args->hotCodeSize = roDataOffset + args->roDataSize; + args->roDataSize = 0; + +#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) info.compCompHnd->allocMem(args); #ifdef DEBUG - if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0)) - { - // Fix up hot/cold code pointers - args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + hotSizeRequest; - args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + hotSizeRequest; - // Reset args' hot/cold code sizes in case caller reads them later - args->hotCodeSize = hotSizeRequest; - args->coldCodeSize = coldSizeRequest; + if (JitConfig.JitFakeProcedureSplitting() && (coldCodeOffset > 0)) + { + // Fix up cold code pointers. Cold section is adjacent to hot section. + assert(args->coldCodeBlock == nullptr); + assert(args->coldCodeBlockRW == nullptr); + args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + coldCodeOffset; + args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + coldCodeOffset; } -#endif + +#endif // DEBUG + +#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + + // Fix up data section pointers. + assert(args->roDataBlock == nullptr); + assert(args->roDataBlockRW == nullptr); + args->roDataBlock = ((BYTE*)args->hotCodeBlock) + roDataOffset; + args->roDataBlockRW = ((BYTE*)args->hotCodeBlockRW) + roDataOffset; + +#endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) } void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwindSize) diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index ebd4f2120585a..eb846e06a0dc6 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -3894,15 +3894,33 @@ void emitter::emitDispJumpList() unsigned int jmpCount = 0; for (instrDescJmp* jmp = emitJumpList; jmp != nullptr; jmp = jmp->idjNext) { - printf("IG%02u IN%04x %3s[%u] -> IG%02u %s\n", jmp->idjIG->igNum, jmp->idDebugOnlyInfo()->idNum, - codeGen->genInsDisplayName(jmp), jmp->idCodeSize(), - ((insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel))->igNum, -#if defined(TARGET_XARCH) - jmp->idjIsRemovableJmpCandidate ? " ; removal candidate" : "" + printf("IG%02u IN%04x %3s[%u]", jmp->idjIG->igNum, jmp->idDebugOnlyInfo()->idNum, + codeGen->genInsDisplayName(jmp), jmp->idCodeSize()); + + if (!jmp->idIsBound()) + { + +#if defined(TARGET_ARM64) + if ((jmp->idInsFmt() == IF_LARGEADR) || (jmp->idInsFmt() == IF_LARGELDC)) + { + printf(" -> %s", getRegName(jmp->idReg1())); + } + else + { + printf(" -> IG%02u", ((insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel))->igNum); + } #else - "" -#endif - ); + printf(" -> IG%02u", ((insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel))->igNum); + +#if defined(TARGET_XARCH) + if (jmp->idjIsRemovableJmpCandidate) + { + printf(" ; removal candidate"); + } +#endif // TARGET_XARCH +#endif // !TARGET_ARM64 + } + printf("\n"); jmpCount += 1; } printf(" total jump count: %u\n", jmpCount); @@ -4045,16 +4063,12 @@ void emitter::emitRecomputeIGoffsets() // // Arguments: // handle - a constant value to display a comment for +// cookie - the cookie stored with the handle // flags - a flag that the describes the handle // -void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag) +void emitter::emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlags flag) { #ifdef DEBUG - if (handle == 0) - { - return; - } - #ifdef TARGET_XARCH const char* commentPrefix = " ;"; #else @@ -4062,8 +4076,35 @@ void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag) #endif flag &= GTF_ICON_HDL_MASK; - const char* str = nullptr; + if (cookie != 0) + { + if (flag == GTF_ICON_FTN_ADDR) + { + const char* className = nullptr; + const char* methName = + emitComp->eeGetMethodName(reinterpret_cast(cookie), &className); + printf("%s code for %s:%s", commentPrefix, className, methName); + return; + } + + if ((flag == GTF_ICON_STATIC_HDL) || (flag == GTF_ICON_STATIC_BOX_PTR)) + { + const char* className = nullptr; + const char* fieldName = + emitComp->eeGetFieldName(reinterpret_cast(cookie), &className); + printf("%s %s for %s%s%s", commentPrefix, flag == GTF_ICON_STATIC_HDL ? "data" : "box", className, + className != nullptr ? ":" : "", fieldName); + return; + } + } + + if (handle == 0) + { + return; + } + + const char* str = nullptr; if (flag == GTF_ICON_STR_HDL) { const WCHAR* wstr = emitComp->eeGetCPString(handle); @@ -4103,8 +4144,6 @@ void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag) { str = emitComp->eeGetClassName(reinterpret_cast(handle)); } -#ifndef TARGET_XARCH - // These are less useful for xarch: else if (flag == GTF_ICON_CONST_PTR) { str = "const ptr"; @@ -4133,11 +4172,6 @@ void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag) { str = "token handle"; } - else - { - str = "unknown"; - } -#endif // TARGET_XARCH if (str != nullptr) { @@ -4527,7 +4561,6 @@ void emitter::emitJumpDistBind() else if (emitIsUncondJump(jmp)) { // Nothing to do; we don't shrink these. - assert(jmp->idjShort); ssz = JMP_SIZE_SMALL; } else if (emitIsLoadLabel(jmp)) @@ -6230,7 +6263,13 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, coldCodeBlock = nullptr; - CorJitAllocMemFlag allocMemFlag = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN; + // This restricts the data alignment to: 4, 8, 16, or 32 bytes + // Alignments greater than 32 would require VM support in ICorJitInfo::allocMem + uint32_t dataAlignment = emitConsDsc.alignment; + assert((dataSection::MIN_DATA_ALIGN <= dataAlignment) && (dataAlignment <= dataSection::MAX_DATA_ALIGN) && + isPow2(dataAlignment)); + + uint32_t codeAlignment = TARGET_POINTER_SIZE; #ifdef TARGET_X86 // @@ -6250,14 +6289,14 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, const weight_t scenarioHotWeight = 256.0; if (emitComp->fgCalledCount > (scenarioHotWeight * emitComp->fgProfileRunsCount())) { - allocMemFlag = CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN; + codeAlignment = 16; } } else { if (emitTotalHotCodeSize <= 16) { - allocMemFlag = CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN; + codeAlignment = 16; } } #endif @@ -6269,61 +6308,46 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, if (emitComp->opts.OptimizationEnabled() && !emitComp->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && (emitTotalHotCodeSize > 16) && emitComp->fgHasLoops) { - allocMemFlag = CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN; + codeAlignment = 32; } #endif - // This restricts the emitConsDsc.alignment to: 1, 2, 4, 8, 16, or 32 bytes - // Alignments greater than 32 would require VM support in ICorJitInfo::allocMem - assert(isPow2(emitConsDsc.alignment) && (emitConsDsc.alignment <= 32)); +#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) + // For arm64/LoongArch64, we're going to put the data in the code section. So make sure the code section has + // adequate alignment. + if (emitConsDsc.dsdOffs > 0) + { + codeAlignment = max(codeAlignment, dataAlignment); + } +#endif - if (emitConsDsc.alignment == 16) + // Note that we don't support forcing code alignment of 8 bytes on 32-bit platforms; an omission? + assert((TARGET_POINTER_SIZE <= codeAlignment) && (codeAlignment <= 32) && isPow2(codeAlignment)); + + CorJitAllocMemFlag allocMemFlagCodeAlign = CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN; + if (codeAlignment == 32) { - allocMemFlag = static_cast(allocMemFlag | CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN); + allocMemFlagCodeAlign = CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN; } - else if (emitConsDsc.alignment == 32) + else if (codeAlignment == 16) { - allocMemFlag = static_cast(allocMemFlag | CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN); + allocMemFlagCodeAlign = CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN; } - AllocMemArgs args; - memset(&args, 0, sizeof(args)); - -#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - // For arm64/LoongArch64, we want to allocate JIT data always adjacent to code similar to what native compiler does. - // This way allows us to use a single `ldr` to access such data like float constant/jmp table. - // For LoongArch64 using `pcaddi + ld` to access such data. - if (emitTotalColdCodeSize > 0) + CorJitAllocMemFlag allocMemFlagDataAlign = static_cast(0); + if (dataAlignment == 16) { - // JIT data might be far away from the cold code. - NYI("Need to handle fix-up to data from cold code."); + allocMemFlagDataAlign = CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN; } - - UNATIVE_OFFSET roDataAlignmentDelta = 0; - if (emitConsDsc.dsdOffs && (emitConsDsc.alignment == TARGET_POINTER_SIZE)) + else if (dataAlignment == 32) { - UNATIVE_OFFSET roDataAlignment = TARGET_POINTER_SIZE; // 8 Byte align by default. - roDataAlignmentDelta = (UNATIVE_OFFSET)ALIGN_UP(emitTotalHotCodeSize, roDataAlignment) - emitTotalHotCodeSize; - assert((roDataAlignmentDelta == 0) || (roDataAlignmentDelta == 4)); + allocMemFlagDataAlign = CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN; } - args.hotCodeSize = emitTotalHotCodeSize + roDataAlignmentDelta + emitConsDsc.dsdOffs; - args.coldCodeSize = emitTotalColdCodeSize; - args.roDataSize = 0; - args.xcptnsCount = xcptnsCount; - args.flag = allocMemFlag; - - emitComp->eeAllocMem(&args); - - codeBlock = (BYTE*)args.hotCodeBlock; - codeBlockRW = (BYTE*)args.hotCodeBlockRW; - coldCodeBlock = (BYTE*)args.coldCodeBlock; - coldCodeBlockRW = (BYTE*)args.coldCodeBlockRW; - - consBlock = codeBlock + emitTotalHotCodeSize + roDataAlignmentDelta; - consBlockRW = codeBlockRW + emitTotalHotCodeSize + roDataAlignmentDelta; + CorJitAllocMemFlag allocMemFlag = static_cast(allocMemFlagCodeAlign | allocMemFlagDataAlign); -#else + AllocMemArgs args; + memset(&args, 0, sizeof(args)); args.hotCodeSize = emitTotalHotCodeSize; args.coldCodeSize = emitTotalColdCodeSize; @@ -6331,7 +6355,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, args.xcptnsCount = xcptnsCount; args.flag = allocMemFlag; - emitComp->eeAllocMem(&args); + emitComp->eeAllocMem(&args, emitConsDsc.alignment); codeBlock = (BYTE*)args.hotCodeBlock; codeBlockRW = (BYTE*)args.hotCodeBlockRW; @@ -6340,13 +6364,27 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, consBlock = (BYTE*)args.roDataBlock; consBlockRW = (BYTE*)args.roDataBlockRW; -#endif - #ifdef DEBUG if ((allocMemFlag & CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN) != 0) { assert(((size_t)codeBlock & 31) == 0); } +#if 0 + // TODO: we should be able to assert the following, but it appears crossgen2 doesn't respect them, + // or maybe it respects them in the written image but not in the buffer pointer given to the JIT. + if ((allocMemFlag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN) != 0) + { + assert(((size_t)codeBlock & 15) == 0); + } + if ((allocMemFlag & CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN) != 0) + { + assert(((size_t)consBlock & 31) == 0); + } + if ((allocMemFlag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN) != 0) + { + assert(((size_t)consBlock & 15) == 0); + } +#endif // 0 #endif // if (emitConsDsc.dsdOffs) @@ -7245,7 +7283,12 @@ UNATIVE_OFFSET emitter::emitDataGenBeg(unsigned size, unsigned alignment, var_ty } assert((secOffs % alignment) == 0); - emitConsDsc.alignment = max(emitConsDsc.alignment, alignment); + if (emitConsDsc.alignment < alignment) + { + JITDUMP("Increasing data section alignment from %u to %u for type %s\n", emitConsDsc.alignment, alignment, + varTypeName(dataType)); + emitConsDsc.alignment = alignment; + } /* Advance the current offset */ emitConsDsc.dsdOffs += size; @@ -7643,7 +7686,7 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, BYTE* dst) if (emitComp->opts.disAsm) { - emitDispDataSec(sec); + emitDispDataSec(sec, dst); } unsigned secNum = 0; @@ -7764,13 +7807,14 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, BYTE* dst) // // Arguments: // section - the data section description +// dst - address of the data section // // Notes: // The output format attempts to mirror typical assembler syntax. // Data section entries lack type information so float/double entries // are displayed as if they are integers/longs. // -void emitter::emitDispDataSec(dataSecDsc* section) +void emitter::emitDispDataSec(dataSecDsc* section, BYTE* dst) { printf("\n"); @@ -7778,11 +7822,17 @@ void emitter::emitDispDataSec(dataSecDsc* section) for (dataSection* data = section->dsdList; data != nullptr; data = data->dsNext) { + if (emitComp->opts.disAddr) + { + printf("; @" FMT_ADDR "\n", DBG_ADDR(dst)); + } + const char* labelFormat = "%-7s"; char label[64]; sprintf_s(label, ArrLen(label), "RWD%02u", offset); printf(labelFormat, label); offset += data->dsSize; + dst += data->dsSize; if ((data->dsType == dataSection::blockRelative32) || (data->dsType == dataSection::blockAbsoluteAddr)) { diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index fc90bd96d6909..d44fd1bd572ee 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -523,7 +523,7 @@ class emitter void emitRecomputeIGoffsets(); - void emitDispCommentForHandle(size_t handle, GenTreeFlags flags); + void emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlags flags); /************************************************************************/ /* The following describes a single instruction */ @@ -554,7 +554,7 @@ class emitter #endif // TARGET_XARCH -#ifdef DEBUG // This information is used in DEBUG builds to display the method name for call instructions +#ifdef DEBUG // This information is used in DEBUG builds for additional diagnostics struct instrDesc; @@ -997,7 +997,7 @@ class emitter case IF_LARGELDC: if (isVectorRegister(idReg1())) { - // adrp + ldr + fmov + // (adrp + ldr + fmov) or (adrp + add + ld1) size = 12; } else @@ -2555,7 +2555,7 @@ class emitter void emitOutputDataSec(dataSecDsc* sec, BYTE* dst); #ifdef DEBUG - void emitDispDataSec(dataSecDsc* section); + void emitDispDataSec(dataSecDsc* section, BYTE* dst); #endif /************************************************************************/ diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index ccf3ddff35709..5e172a0914a6d 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -7678,6 +7678,62 @@ void emitter::emitDispInsHelp( printf("\n"); } +/***************************************************************************** + * + * Handles printing of LARGEJMP pseudo-instruction. + */ + +void emitter::emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig) +{ + // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very + // difficult to find bug. + + instrDescJmp idJmp; + instrDescJmp* pidJmp = &idJmp; + + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the + // conditional + // instruction + pidJmp->idInsFmt(IF_T1_K); + pidJmp->idInsSize(emitInsSize(IF_T1_K)); + pidJmp->idjShort = 1; + pidJmp->idAddr()->iiaSetInstrCount(1); + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field + + size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes + emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero, + NULL /* force display of pc-relative branch */); + + code += bcondSizeOrZero; + offset += 2; + + // Next, display the unconditional branch + + // Reset the local instrDesc + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(INS_b); + pidJmp->idInsFmt(IF_T2_J2); + pidJmp->idInsSize(emitInsSize(IF_T2_J2)); + pidJmp->idjShort = 0; + if (id->idIsBound()) + { + pidJmp->idSetIsBound(); + pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; + } + else + { + pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; + } + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field + + size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes + emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig); +} + //-------------------------------------------------------------------- // emitDispIns: Dump the given instruction to jitstdout. // @@ -7714,53 +7770,7 @@ void emitter::emitDispIns( // // These instructions don't exist in the actual instruction stream, so we need to fake them // up to display them. - // - // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very - // difficult to find bug. - - instrDescJmp idJmp; - instrDescJmp* pidJmp = &idJmp; - - memset(&idJmp, 0, sizeof(idJmp)); - - pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the - // conditional - // instruction - pidJmp->idInsFmt(IF_T1_K); - pidJmp->idInsSize(emitInsSize(IF_T1_K)); - pidJmp->idjShort = 1; - pidJmp->idAddr()->iiaSetInstrCount(1); - pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field - - size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes - emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero, - NULL /* force display of pc-relative branch */); - - code += bcondSizeOrZero; - offset += 2; - - // Next, display the unconditional branch - - // Reset the local instrDesc - memset(&idJmp, 0, sizeof(idJmp)); - - pidJmp->idIns(INS_b); - pidJmp->idInsFmt(IF_T2_J2); - pidJmp->idInsSize(emitInsSize(IF_T2_J2)); - pidJmp->idjShort = 0; - if (id->idIsBound()) - { - pidJmp->idSetIsBound(); - pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; - } - else - { - pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; - } - pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field - - size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes - emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig); + emitDispLargeJmp(id, isNew, doffs, asmfm, offset, code, sz, ig); } else { diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h index 09133a1d88f02..c40c5fb85f9c5 100644 --- a/src/coreclr/jit/emitarm.h +++ b/src/coreclr/jit/emitarm.h @@ -43,6 +43,14 @@ void emitDispAddrRR(regNumber reg1, regNumber reg2, emitAttr attr); void emitDispAddrRRI(regNumber reg1, regNumber reg2, int imm, emitAttr attr); void emitDispAddrPUW(regNumber reg, int imm, insOpts opt, emitAttr attr); void emitDispGC(emitAttr attr); +void emitDispLargeJmp(instrDesc* id, + bool isNew, + bool doffs, + bool asmfm, + unsigned offs = 0, + BYTE* code = 0, + size_t sz = 0, + insGroup* ig = NULL); void emitDispInsHelp(instrDesc* id, bool isNew, diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 864ba862edddd..b0bf1769d1bd0 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -3740,7 +3740,8 @@ void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, - insOpts opt /* = INS_OPTS_NONE */ DEBUGARG(GenTreeFlags gtFlags)) + insOpts opt /* = INS_OPTS_NONE */ + DEBUGARG(size_t targetHandle /* = 0 */) DEBUGARG(GenTreeFlags gtFlags /* = GTF_EMPTY */)) { emitAttr size = EA_SIZE(attr); emitAttr elemsize = EA_UNKNOWN; @@ -3990,7 +3991,11 @@ void emitter::emitIns_R_I(instruction ins, id->idInsOpt(opt); id->idReg1(reg); - INDEBUG(id->idDebugOnlyInfo()->idFlags = gtFlags); + +#ifdef DEBUG + id->idDebugOnlyInfo()->idMemCookie = targetHandle; + id->idDebugOnlyInfo()->idFlags = gtFlags; +#endif dispIns(id); appendToCurIG(id); @@ -4503,14 +4508,16 @@ void emitter::emitIns_R_R( case INS_str: case INS_strb: case INS_strh: - - case INS_cmp: case INS_cmn: case INS_tst: assert(insOptsNone(opt)); emitIns_R_R_I(ins, attr, reg1, reg2, 0, INS_OPTS_NONE); return; + case INS_cmp: + emitIns_R_R_I(ins, attr, reg1, reg2, 0, opt); + return; + case INS_staddb: emitIns_R_R_R(INS_ldaddb, attr, reg1, REG_ZR, reg2); return; @@ -4927,8 +4934,13 @@ void emitter::emitIns_R_R( * Add an instruction referencing a register and two constants. */ -void emitter::emitIns_R_I_I( - instruction ins, emitAttr attr, regNumber reg, ssize_t imm1, ssize_t imm2, insOpts opt /* = INS_OPTS_NONE */) +void emitter::emitIns_R_I_I(instruction ins, + emitAttr attr, + regNumber reg, + ssize_t imm1, + ssize_t imm2, + insOpts opt /* = INS_OPTS_NONE */ + DEBUGARG(size_t targetHandle /* = 0 */) DEBUGARG(GenTreeFlags gtFlags /* = 0 */)) { emitAttr size = EA_SIZE(attr); insFormat fmt = IF_NONE; @@ -5015,6 +5027,11 @@ void emitter::emitIns_R_I_I( id->idReg1(reg); +#ifdef DEBUG + id->idDebugOnlyInfo()->idFlags = gtFlags; + id->idDebugOnlyInfo()->idMemCookie = targetHandle; +#endif + dispIns(id); appendToCurIG(id); } @@ -8421,10 +8438,12 @@ void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount) switch (ins) { case INS_bl_local: + idjShort = true; + FALLTHROUGH; case INS_b: // Unconditional jump is a single form. - idjShort = true; - fmt = IF_BI_0A; + // Assume is long in case we cross hot/cold sections. + fmt = IF_BI_0A; break; case INS_beq: @@ -8469,7 +8488,6 @@ void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount) id->idAddr()->iiaBBlabel = dst; // Skip unconditional jump that has a single form. - // TODO-ARM64-NYI: enable hot/cold splittingNYI. // The target needs to be relocated. if (!idjShort) { @@ -9799,38 +9817,67 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) { // Update addrReg with the reserved integer register // since we cannot use dstReg (vector) to load constant directly from memory. - addrReg = id->idReg2(); + + // If loading a 16-byte value, we will need to load directly into dstReg. + // Thus, encode addrReg for the ld1 instruction. + if (opSize == EA_16BYTE) + { + addrReg = encodingSPtoZR(id->idReg2()); + } + else + { + addrReg = id->idReg2(); + } + assert(isGeneralRegister(addrReg)); } + ins = INS_adrp; fmt = IF_DI_1E; dst = emitOutputShortAddress(dst, ins, fmt, relPageAddr, addrReg); - // ldr x, [x, page offs] -- load constant from page address + page offset into integer register. ssize_t imm12 = (ssize_t)dstAddr & 0xFFF; // 12 bits assert(isValidUimm12(imm12)); - ins = INS_ldr; - fmt = IF_LS_2B; - dst = emitOutputShortConstant(dst, ins, fmt, imm12, addrReg, opSize); - // fmov v, d -- copy constant in integer register to vector register. - // This is needed only for vector constant. - if (addrReg != dstReg) + // Special case: emit add + ld1 instructions for loading 16-byte data into vector register. + if (isVectorRegister(dstReg) && (opSize == EA_16BYTE)) { - // fmov Vd,Rn DV_2I X00111100X100111 000000nnnnnddddd 1E27 0000 Vd,Rn - // (scalar, from general) - assert(isVectorRegister(dstReg) && isGeneralRegister(addrReg)); - ins = INS_fmov; - fmt = IF_DV_2I; - code_t code = emitInsCode(ins, fmt); + const emitAttr elemSize = EA_1BYTE; + const insOpts opt = optMakeArrangement(opSize, elemSize); - code |= insEncodeReg_Vd(dstReg); // ddddd - code |= insEncodeReg_Rn(addrReg); // nnnnn - if (id->idOpSize() == EA_8BYTE) + assert(isGeneralRegisterOrSP(addrReg)); + assert(isValidVectorElemsize(elemSize)); + assert(isValidArrangement(opSize, opt)); + + // Calculate page addr + page offs, then emit ld1 instruction. + dst = emitOutputVectorConstant(dst, imm12, dstReg, addrReg, opSize, elemSize); + } + else + { + // ldr x, [x, 0] -- load constant from address into integer register. + ins = INS_ldr; + fmt = IF_LS_2B; + dst = emitOutputShortConstant(dst, ins, fmt, imm12, addrReg, opSize); + + // fmov v, d -- copy constant in integer register to vector register. + // This is needed only for vector constant. + if (addrReg != dstReg) { - code |= 0x80400000; // X ... X + // fmov Vd,Rn DV_2I X00111100X100111 000000nnnnnddddd 1E27 0000 Vd,Rn + // (scalar, from general) + assert(isVectorRegister(dstReg) && isGeneralRegister(addrReg)); + ins = INS_fmov; + fmt = IF_DV_2I; + code_t code = emitInsCode(ins, fmt); + + code |= insEncodeReg_Vd(dstReg); // ddddd + code |= insEncodeReg_Rn(addrReg); // nnnnn + if (id->idOpSize() == EA_8BYTE) + { + code |= 0x80400000; // X ... X + } + dst += emitOutput_Instr(dst, code); } - dst += emitOutput_Instr(dst, code); } } } @@ -9933,12 +9980,6 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) /* For forward jumps, record the address of the distance value */ id->idjTemp.idjAddr = (distVal > 0) ? dst : NULL; - if (emitJumpCrossHotColdBoundary(srcOffs, dstOffs)) - { - assert(!id->idjShort); - NYI_ARM64("Relocation Support for long address"); - } - assert(insOptsNone(id->idInsOpt())); if (isJump) @@ -9949,75 +9990,114 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) assert(!id->idjKeepLong); assert(emitJumpCrossHotColdBoundary(srcOffs, dstOffs) == false); assert((fmt == IF_BI_0A) || (fmt == IF_BI_0B) || (fmt == IF_BI_1A) || (fmt == IF_BI_1B)); + dst = emitOutputShortBranch(dst, ins, fmt, distVal, id); } else { - // Long conditional jump - assert(fmt == IF_LARGEJMP); - // This is a pseudo-instruction format representing a large conditional branch, to allow - // us to get a greater branch target range than we can get by using a straightforward conditional - // branch. It is encoded as a short conditional branch that branches around a long unconditional - // branch. - // - // Conceptually, we have: - // - // b L_target - // - // The code we emit is: - // - // b L_not // 4 bytes. Note that we reverse the condition. - // b L_target // 4 bytes - // L_not: - // - // Note that we don't actually insert any blocks: we simply encode "b L_not" as a branch with - // the correct offset. Note also that this works for both integer and floating-point conditions, because - // the condition inversion takes ordered/unordered into account, preserving NaN behavior. For example, - // "GT" (greater than) is inverted to "LE" (less than, equal, or unordered). + // Long conditional/unconditional jump - instruction reverseIns; - insFormat reverseFmt; + if (fmt == IF_LARGEJMP) + { + // This is a pseudo-instruction format representing a large conditional branch, to allow + // us to get a greater branch target range than we can get by using a straightforward conditional + // branch. It is encoded as a short conditional branch that branches around a long unconditional + // branch. + // + // Conceptually, we have: + // + // b L_target + // + // The code we emit is: + // + // b L_not // 4 bytes. Note that we reverse the condition. + // b L_target // 4 bytes + // L_not: + // + // Note that we don't actually insert any blocks: we simply encode "b L_not" as a branch with + // the correct offset. Note also that this works for both integer and floating-point conditions, because + // the condition inversion takes ordered/unordered into account, preserving NaN behavior. For example, + // "GT" (greater than) is inverted to "LE" (less than, equal, or unordered). - switch (ins) + instruction reverseIns; + insFormat reverseFmt; + + switch (ins) + { + case INS_cbz: + reverseIns = INS_cbnz; + reverseFmt = IF_BI_1A; + break; + case INS_cbnz: + reverseIns = INS_cbz; + reverseFmt = IF_BI_1A; + break; + case INS_tbz: + reverseIns = INS_tbnz; + reverseFmt = IF_BI_1B; + break; + case INS_tbnz: + reverseIns = INS_tbz; + reverseFmt = IF_BI_1B; + break; + default: + reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins))); + reverseFmt = IF_BI_0B; + } + + dst = emitOutputShortBranch(dst, + reverseIns, // reverse the conditional instruction + reverseFmt, 8, /* 8 bytes from start of this large conditional + pseudo-instruction to L_not. */ + id); + + // Now, pretend we've got a normal unconditional branch, and fall through to the code to emit that. + ins = INS_b; + fmt = IF_BI_0A; + + // The distVal was computed based on the beginning of the pseudo-instruction, + // So subtract the size of the conditional branch so that it is relative to the + // unconditional branch. + distVal -= 4; + } + + assert(fmt == IF_BI_0A); + assert((distVal & 1) == 0); + code_t code = emitInsCode(ins, fmt); + const bool recordRelocation = emitComp->opts.compReloc && emitJumpCrossHotColdBoundary(srcOffs, dstOffs); + + if (recordRelocation) { - case INS_cbz: - reverseIns = INS_cbnz; - reverseFmt = IF_BI_1A; - break; - case INS_cbnz: - reverseIns = INS_cbz; - reverseFmt = IF_BI_1A; - break; - case INS_tbz: - reverseIns = INS_tbnz; - reverseFmt = IF_BI_1B; - break; - case INS_tbnz: - reverseIns = INS_tbz; - reverseFmt = IF_BI_1B; - break; - default: - reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins))); - reverseFmt = IF_BI_0B; + // dst isn't an actual final target location, just some intermediate + // location. Thus we cannot make any guarantees about distVal (not + // even the direction/sign). Instead we don't encode any offset and + // rely on the relocation to do all the work } + else + { + // Branch offset encodings are scaled by 4. + noway_assert((distVal & 3) == 0); + distVal >>= 2; + noway_assert(isValidSimm26(distVal)); - dst = - emitOutputShortBranch(dst, - reverseIns, // reverse the conditional instruction - reverseFmt, - 8, /* 8 bytes from start of this large conditional pseudo-instruction to L_not. */ - id); + // Insert offset into unconditional branch instruction + distVal &= 0x3FFFFFFLL; + code |= distVal; + } - // Now, pretend we've got a normal unconditional branch, and fall through to the code to emit that. - ins = INS_b; - fmt = IF_BI_0A; + const unsigned instrSize = emitOutput_Instr(dst, code); - // The distVal was computed based on the beginning of the pseudo-instruction, - // So subtract the size of the conditional branch so that it is relative to the - // unconditional branch. - distVal -= 4; - } + if (recordRelocation) + { + assert(id->idjKeepLong); + if (emitComp->info.compMatchedVM) + { + void* target = emitOffsetToPtr(dstOffs); + emitRecordRelocation((void*)dst, target, IMAGE_REL_ARM64_BRANCH26); + } + } - dst = emitOutputShortBranch(dst, ins, fmt, distVal, id); + dst += instrSize; + } } else if (loadLabel) { @@ -10138,7 +10218,7 @@ BYTE* emitter::emitOutputShortConstant( ssize_t loBits = (imm & 3); noway_assert(loBits == 0); - ssize_t distVal = imm >>= 2; // load offset encodings are scaled by 4. + ssize_t distVal = imm >> 2; // load offset encodings are scaled by 4. noway_assert(isValidSimm19(distVal)); @@ -10206,6 +10286,33 @@ BYTE* emitter::emitOutputShortConstant( return dst; } + +/***************************************************************************** + * + * Output instructions to load a constant into a vector register. + */ +BYTE* emitter::emitOutputVectorConstant( + BYTE* dst, ssize_t imm, regNumber dstReg, regNumber addrReg, emitAttr opSize, emitAttr elemSize) +{ + // add addrReg, addrReg, page offs -- compute address = page addr + page offs. + code_t code = emitInsCode(INS_add, IF_DI_2A); // DI_2A X0010001shiiiiii iiiiiinnnnnddddd 1100 0000 imm(i12, sh) + code |= insEncodeDatasize(EA_8BYTE); // X - use EA_8BYTE, as we are calculating 64-bit address + code |= ((code_t)imm << 10); // iiiiiiiiiiii + code |= insEncodeReg_Rd(addrReg); // ddddd + code |= insEncodeReg_Rn(addrReg); // nnnnn + dst += emitOutput_Instr(dst, code); + + // ld1 dstReg, addrReg -- load constant at address in addrReg into dstReg. + code = emitInsCode(INS_ld1, IF_LS_2D); // LS_2D .Q.............. ....ssnnnnnttttt Vt Rn + code |= insEncodeVectorsize(opSize); // Q + code |= insEncodeVLSElemsize(elemSize); // ss + code |= insEncodeReg_Rn(addrReg); // nnnnn + code |= insEncodeReg_Vt(dstReg); // ttttt + dst += emitOutput_Instr(dst, code); + + return dst; +} + /***************************************************************************** * * Output a call instruction. @@ -12241,8 +12348,121 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) } } +/***************************************************************************** + * + * Handles printing of LARGEJMP pseudo-instruction. + */ + +void emitter::emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) +{ + // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very + // difficult-to-find bug. + + instrDescJmp idJmp; + instrDescJmp* pidJmp = &idJmp; + + memset(&idJmp, 0, sizeof(idJmp)); + + const instruction ins = id->idIns(); + instruction reverseIns; + insFormat reverseFmt; + + // Reverse the conditional instruction. + switch (ins) + { + case INS_cbz: + reverseIns = INS_cbnz; + reverseFmt = IF_BI_1A; + break; + case INS_cbnz: + reverseIns = INS_cbz; + reverseFmt = IF_BI_1A; + break; + case INS_tbz: + reverseIns = INS_tbnz; + reverseFmt = IF_BI_1B; + break; + case INS_tbnz: + reverseIns = INS_tbz; + reverseFmt = IF_BI_1B; + break; + default: + reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins))); + reverseFmt = IF_BI_0B; + } + + pidJmp->idIns(reverseIns); + pidJmp->idInsFmt(reverseFmt); + pidJmp->idOpSize(id->idOpSize()); + pidJmp->idAddr()->iiaSetInstrCount(1); + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field. + + const size_t bcondSizeOrZero = (pCode == NULL) ? 0 : 4; // Branch is 4 bytes. + emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, pCode, bcondSizeOrZero, + NULL /* force display of pc-relative branch */); + + pCode += bcondSizeOrZero; + offset += 4; + + // Next, display the unconditional branch. + + // Reset the local instrDesc. + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(INS_b); + pidJmp->idInsFmt(IF_LARGEJMP); + + if (id->idIsBound()) + { + pidJmp->idSetIsBound(); + pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; + } + else + { + pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; + } + + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field. + + const size_t brSizeOrZero = (pCode == NULL) ? 0 : 4; // Unconditional branch is 4 bytes. + emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, pCode, brSizeOrZero, ig); +} + +/***************************************************************************** + * + * Wrapper for emitter::emitDispInsHelp() that handles special large jump + * pseudo-instruction. + */ + +void emitter::emitDispIns( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) +{ + // Special case: IF_LARGEJMP + + if ((id->idInsFmt() == IF_LARGEJMP) && id->idIsBound()) + { + // This is a pseudo-instruction format representing a large conditional branch. See the comment + // in emitter::emitOutputLJ() for the full description. + // + // For this pseudo-instruction, we will actually generate: + // + // b L_not // 4 bytes. Note that we reverse the condition. + // b L_target // 4 bytes. + // L_not: + // + // These instructions don't exist in the actual instruction stream, so we need to fake them + // up to display them. + emitDispLargeJmp(id, isNew, doffs, asmfm, offset, pCode, sz, ig); + } + else + { + emitDispInsHelp(id, isNew, doffs, asmfm, offset, pCode, sz, ig); + } +} + //-------------------------------------------------------------------- -// emitDispIns: Dump the given instruction to jitstdout. +// emitDispInsHelp: Dump the given instruction to jitstdout. // // Arguments: // id - The instruction @@ -12257,7 +12477,7 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) // sz - The size of the instruction, used to display the encoded bytes. // ig - The instruction group containing the instruction. // -void emitter::emitDispIns( +void emitter::emitDispInsHelp( instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) { if (EMITVERBOSE) @@ -12269,7 +12489,9 @@ void emitter::emitDispIns( } if (pCode == NULL) + { sz = 0; + } if (!isNew && !asmfm && sz) { @@ -12379,23 +12601,34 @@ void emitter::emitDispIns( break; case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00 + case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00 + { assert(insOptsNone(id->idInsOpt())); emitDispReg(id->idReg1(), size, true); - if (id->idIsBound()) + + if (fmt == IF_BI_1B) { - emitPrintLabel(id->idAddr()->iiaIGlabel); + emitDispImm(emitGetInsSC(id), true); } - else + + if (id->idAddr()->iiaHasInstrCount()) { - printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum); - } - break; + int instrCount = id->idAddr()->iiaGetInstrCount(); - case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00 - assert(insOptsNone(id->idInsOpt())); - emitDispReg(id->idReg1(), size, true); - emitDispImm(emitGetInsSC(id), true); - if (id->idIsBound()) + if (ig == nullptr) + { + printf("pc%s%d instructions", (instrCount >= 0) ? "+" : "", instrCount); + } + else + { + unsigned insNum = emitFindInsNum(ig, id); + UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1); + UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount); + ssize_t relOffs = (ssize_t)(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs)); + printf("pc%s%d (%d instructions)", (relOffs >= 0) ? "+" : "", relOffs, instrCount); + } + } + else if (id->idIsBound()) { emitPrintLabel(id->idAddr()->iiaIGlabel); } @@ -12403,7 +12636,8 @@ void emitter::emitDispIns( { printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum); } - break; + } + break; case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn assert(insOptsNone(id->idInsOpt())); @@ -12487,7 +12721,7 @@ void emitter::emitDispIns( } else { - emitDispCommentForHandle(id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); + emitDispCommentForHandle(id->idDebugOnlyInfo()->idMemCookie, 0, id->idDebugOnlyInfo()->idFlags); } break; @@ -12623,6 +12857,7 @@ void emitter::emitDispIns( case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh) emitDispReg(id->idReg1(), size, true); emitDispImmOptsLSL12(emitGetInsSC(id), id->idInsOpt()); + emitDispCommentForHandle(0, id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); break; case IF_DI_1B: // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw) @@ -12641,18 +12876,21 @@ void emitter::emitDispIns( emitDispImm(hwi.immHW * 16, false); } } + emitDispCommentForHandle(0, id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); break; case IF_DI_1C: // DI_1C X........Nrrrrrr ssssssnnnnn..... Rn imm(N,r,s) emitDispReg(id->idReg1(), size, true); bmi.immNRS = (unsigned)emitGetInsSC(id); emitDispImm(emitDecodeBitMaskImm(bmi, size), false); + emitDispCommentForHandle(0, id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); break; case IF_DI_1D: // DI_1D X........Nrrrrrr ssssss.....ddddd Rd imm(N,r,s) emitDispReg(encodingZRtoSP(id->idReg1()), size, true); bmi.immNRS = (unsigned)emitGetInsSC(id); emitDispImm(emitDecodeBitMaskImm(bmi, size), false); + emitDispCommentForHandle(0, id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); break; case IF_DI_2A: // DI_2A X.......shiiiiii iiiiiinnnnnddddd Rd Rn imm(i12,sh) diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 8970c15b3c090..4068fe3c25408 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -23,6 +23,10 @@ static bool strictArmAsm; const char* emitVectorRegName(regNumber reg); +void emitDispInsHelp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig); +void emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig); void emitDispInst(instruction ins); void emitDispImm(ssize_t imm, bool addComma, bool alwaysHex = false); void emitDispFloatZero(); @@ -726,7 +730,8 @@ void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, - insOpts opt = INS_OPTS_NONE DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); + insOpts opt = INS_OPTS_NONE DEBUGARG(size_t targetHandle = 0) + DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); void emitIns_R_F(instruction ins, emitAttr attr, regNumber reg, double immDbl, insOpts opt = INS_OPTS_NONE); @@ -740,8 +745,13 @@ void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, emitIns_R_R(ins, attr, reg1, reg2); } -void emitIns_R_I_I( - instruction ins, emitAttr attr, regNumber reg1, ssize_t imm1, ssize_t imm2, insOpts opt = INS_OPTS_NONE); +void emitIns_R_I_I(instruction ins, + emitAttr attr, + regNumber reg1, + ssize_t imm1, + ssize_t imm2, + insOpts opt = INS_OPTS_NONE DEBUGARG(size_t targetHandle = 0) + DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); void emitIns_R_R_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt = INS_OPTS_NONE); @@ -867,6 +877,8 @@ BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t d BYTE* emitOutputShortAddress(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg); BYTE* emitOutputShortConstant( BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg, emitAttr opSize); +BYTE* emitOutputVectorConstant( + BYTE* dst, ssize_t distVal, regNumber dstReg, regNumber addrReg, emitAttr opSize, emitAttr elemSize); /***************************************************************************** * diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 8e3802123dd5a..57987606a903c 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -3912,7 +3912,7 @@ static const char* const RegNames[] = void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) { - const BYTE* insAdr = addr; + const BYTE* insAdr = addr - writeableOffset; const char* const CFregName[] = {"fcc0", "fcc1", "fcc2", "fcc3", "fcc4", "fcc5", "fcc6", "fcc7"}; unsigned int opcode = (code >> 26) & 0x3f; diff --git a/src/coreclr/jit/emitloongarch64.h b/src/coreclr/jit/emitloongarch64.h index d7e7cc5450acb..da24986527182 100644 --- a/src/coreclr/jit/emitloongarch64.h +++ b/src/coreclr/jit/emitloongarch64.h @@ -133,6 +133,12 @@ inline static bool isFloatReg(regNumber reg) return (reg >= REG_FP_FIRST && reg <= REG_FP_LAST); } +/************************************************************************/ +/* Output target-independent instructions */ +/************************************************************************/ + +void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0); + /************************************************************************/ /* The public entry points to output instructions */ /************************************************************************/ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 707c8fc25f7c3..bd5b2d0defe6a 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -3219,6 +3219,11 @@ void emitter::emitHandleMemOp(GenTreeIndir* indir, instrDesc* id, insFormat fmt, id->idAddr()->iiaFieldHnd = fldHnd; id->idInsFmt(emitMapFmtForIns(emitMapFmtAtoM(fmt), ins)); + +#ifdef DEBUG + id->idDebugOnlyInfo()->idFlags = GTF_ICON_STATIC_HDL; + id->idDebugOnlyInfo()->idMemCookie = reinterpret_cast(fldHnd); +#endif } else if ((memBase != nullptr) && memBase->IsCnsIntOrI() && memBase->isContained()) { @@ -3279,6 +3284,14 @@ void emitter::emitHandleMemOp(GenTreeIndir* indir, instrDesc* id, insFormat fmt, // disp must have already been set in the instrDesc constructor. assert(emitGetInsAmdAny(id) == indir->Offset()); // make sure "disp" is stored properly } + +#ifdef DEBUG + if ((memBase != nullptr) && memBase->IsIconHandle() && memBase->isContained()) + { + id->idDebugOnlyInfo()->idFlags = memBase->gtFlags; + id->idDebugOnlyInfo()->idMemCookie = memBase->AsIntCon()->gtTargetHandle; + } +#endif } // Takes care of storing all incoming register parameters @@ -4126,7 +4139,10 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg) * Add an instruction referencing a register and a constant. */ -void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val DEBUGARG(GenTreeFlags gtFlags)) +void emitter::emitIns_R_I(instruction ins, + emitAttr attr, + regNumber reg, + ssize_t val DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags)) { emitAttr size = EA_SIZE(attr); @@ -4259,7 +4275,11 @@ void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t id->idInsFmt(fmt); id->idReg1(reg); id->idCodeSize(sz); - INDEBUG(id->idDebugOnlyInfo()->idFlags = gtFlags); + +#ifdef DEBUG + id->idDebugOnlyInfo()->idFlags = gtFlags; + id->idDebugOnlyInfo()->idMemCookie = targetHandle; +#endif dispIns(id); emitCurIGsize += sz; @@ -9118,7 +9138,7 @@ void emitter::emitDispIns( { // (val < 0) printf("-0x%IX", -val); } - emitDispCommentForHandle(srcVal, id->idDebugOnlyInfo()->idFlags); + emitDispCommentForHandle(srcVal, id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags); } break; @@ -9189,6 +9209,9 @@ void emitter::emitDispIns( } printf("%s, %s", emitRegName(id->idReg1(), attr), sstr); emitDispAddrMode(id); + + emitDispCommentForHandle(emitGetInsAmdAny(id), id->idDebugOnlyInfo()->idMemCookie, + id->idDebugOnlyInfo()->idFlags); break; case IF_RRW_ARD_CNS: diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h index 754632bb1c089..c744e40dbd41e 100644 --- a/src/coreclr/jit/emitxarch.h +++ b/src/coreclr/jit/emitxarch.h @@ -330,7 +330,10 @@ void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int void emitIns_A(instruction ins, emitAttr attr, GenTreeIndir* indir); -void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); +void emitIns_R_I(instruction ins, + emitAttr attr, + regNumber reg, + ssize_t val DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY)); void emitIns_Mov(instruction ins, emitAttr attr, regNumber dstReg, regNumber srgReg, bool canSkip); diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 148dc02af9649..541bdc27e7c96 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -186,7 +186,7 @@ void Compiler::fgInit() fgPgoInlineeNoPgo = 0; fgPgoInlineeNoPgoSingleBlock = 0; fgCountInstrumentor = nullptr; - fgClassInstrumentor = nullptr; + fgHistogramInstrumentor = nullptr; fgPredListSortVector = nullptr; } diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index fe0746aa26d72..d59301991aaa6 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -274,7 +274,7 @@ void Compiler::fgNoteNonInlineCandidate(Statement* stmt, GenTreeCall* call) return; } - InlineResult inlineResult(this, call, nullptr, "fgNoteNonInlineCandidate"); + InlineResult inlineResult(this, call, nullptr, "fgNoteNonInlineCandidate", false); InlineObservation currentObservation = InlineObservation::CALLSITE_NOT_CANDIDATE; // Try and recover the reason left behind when the jit decided @@ -288,7 +288,6 @@ void Compiler::fgNoteNonInlineCandidate(Statement* stmt, GenTreeCall* call) // Propagate the prior failure observation to this result. inlineResult.NotePriorFailure(currentObservation); - inlineResult.SetReported(); if (call->gtCallType == CT_USER_FUNC) { diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index d0d4ae647ec98..360633d901e93 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -3221,8 +3221,10 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) if (verbose) { printf("\nConverting a switch (" FMT_BB ") with only one significant clause besides a default target to a " - "conditional branch\n", + "conditional branch. Before:\n", block->bbNum); + + gtDispTree(switchTree); } #endif // DEBUG @@ -3247,6 +3249,9 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) block->bbJumpDest = block->bbJumpSwt->bbsDstTab[0]; block->bbJumpKind = BBJ_COND; + JITDUMP("After:\n"); + DISPNODE(switchTree); + return true; } return returnvalue; diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp index bfd7000486c8b..4eb555a65ca94 100644 --- a/src/coreclr/jit/fgprofile.cpp +++ b/src/coreclr/jit/fgprofile.cpp @@ -1425,11 +1425,11 @@ void EfficientEdgeCountInstrumentor::Instrument(BasicBlock* block, Schema& schem } //------------------------------------------------------------------------ -// ClassProbeVisitor: invoke functor on each virtual call or cast-related +// HandleHistogramProbeVisitor: invoke functor on each virtual call or cast-related // helper calls in a tree // template -class ClassProbeVisitor final : public GenTreeVisitor> +class HandleHistogramProbeVisitor final : public GenTreeVisitor> { public: enum @@ -1440,26 +1440,17 @@ class ClassProbeVisitor final : public GenTreeVisitor(compiler), m_functor(functor), m_compiler(compiler) + HandleHistogramProbeVisitor(Compiler* compiler, TFunctor& functor) + : GenTreeVisitor(compiler), m_functor(functor), m_compiler(compiler) { } Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user) { GenTree* const node = *use; - if (node->IsCall() && (node->AsCall()->gtClassProfileCandidateInfo != nullptr)) + if (node->IsCall() && (m_compiler->compClassifyGDVProbeType(node->AsCall()) != Compiler::GDVProbeType::None)) { - GenTreeCall* const call = node->AsCall(); - if (call->IsVirtual() && (call->gtCallType != CT_INDIRECT)) - { - // virtual call - m_functor(m_compiler, call); - } - else if (m_compiler->impIsCastHelperEligibleForClassProbe(call)) - { - // isinst/cast helper - m_functor(m_compiler, call); - } + assert(node->AsCall()->gtHandleHistogramProfileCandidateInfo != nullptr); + m_functor(m_compiler, node->AsCall()); } return Compiler::WALK_CONTINUE; @@ -1467,44 +1458,65 @@ class ClassProbeVisitor final : public GenTreeVisitorcompClassifyGDVProbeType(call); + + if ((probeType == Compiler::GDVProbeType::ClassProfile) || + (probeType == Compiler::GDVProbeType::MethodAndClassProfile)) + { + CreateHistogramSchemaEntries(compiler, call, true /* isTypeHistogram */); + } + + if ((probeType == Compiler::GDVProbeType::MethodProfile) || + (probeType == Compiler::GDVProbeType::MethodAndClassProfile)) + { + CreateHistogramSchemaEntries(compiler, call, false /* isTypeHistogram */); + } + } + + void CreateHistogramSchemaEntries(Compiler* compiler, GenTreeCall* call, bool isTypeHistogram) + { + ICorJitInfo::PgoInstrumentationSchema schemaElem = {}; + schemaElem.Count = 1; + schemaElem.Other = isTypeHistogram ? ICorJitInfo::HandleHistogram32::CLASS_FLAG : 0; if (call->IsVirtualStub()) { - schemaElem.Other |= ICorJitInfo::ClassProfile32::INTERFACE_FLAG; + schemaElem.Other |= ICorJitInfo::HandleHistogram32::INTERFACE_FLAG; } - else + else if (call->IsDelegateInvoke()) { - assert(call->IsVirtualVtable() || compiler->impIsCastHelperEligibleForClassProbe(call)); + schemaElem.Other |= ICorJitInfo::HandleHistogram32::DELEGATE_FLAG; } schemaElem.InstrumentationKind = JitConfig.JitCollect64BitCounts() ? ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount : ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount; - schemaElem.ILOffset = (int32_t)call->gtClassProfileCandidateInfo->ilOffset; + schemaElem.ILOffset = (int32_t)call->gtHandleHistogramProfileCandidateInfo->ilOffset; schemaElem.Offset = 0; m_schema.push_back(schemaElem); + m_schemaCount++; + // Re-using ILOffset and Other fields from schema item for TypeHandleHistogramCount - schemaElem.InstrumentationKind = ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes; - schemaElem.Count = ICorJitInfo::ClassProfile32::SIZE; + schemaElem.InstrumentationKind = isTypeHistogram ? ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes + : ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods; + schemaElem.Count = ICorJitInfo::HandleHistogram32::SIZE; m_schema.push_back(schemaElem); m_schemaCount++; @@ -1512,9 +1524,9 @@ class BuildClassProbeSchemaGen }; //------------------------------------------------------------------------ -// ClassProbeInserter: functor that adds class probe instrumentation +// HandleHistogramProbeInserter: functor that adds class/method probe instrumentation // -class ClassProbeInserter +class HandleHistogramProbeInserter { Schema& m_schema; uint8_t* m_profileMemory; @@ -1522,7 +1534,7 @@ class ClassProbeInserter unsigned& m_instrCount; public: - ClassProbeInserter(Schema& schema, uint8_t* profileMemory, int* pCurrentSchemaIndex, unsigned& instrCount) + HandleHistogramProbeInserter(Schema& schema, uint8_t* profileMemory, int* pCurrentSchemaIndex, unsigned& instrCount) : m_schema(schema) , m_profileMemory(profileMemory) , m_currentSchemaIndex(pCurrentSchemaIndex) @@ -1533,10 +1545,11 @@ class ClassProbeInserter void operator()(Compiler* compiler, GenTreeCall* call) { JITDUMP("Found call [%06u] with probe index %d and ilOffset 0x%X\n", compiler->dspTreeID(call), - call->gtClassProfileCandidateInfo->probeIndex, call->gtClassProfileCandidateInfo->ilOffset); + call->gtHandleHistogramProfileCandidateInfo->probeIndex, + call->gtHandleHistogramProfileCandidateInfo->ilOffset); // We transform the call from (CALLVIRT obj, ... args ...) to - // to + // // (CALLVIRT // (COMMA // (ASG tmp, obj) @@ -1546,19 +1559,25 @@ class ClassProbeInserter // ... args ...) // - // Sanity check that we're looking at the right schema entry - // - assert(m_schema[*m_currentSchemaIndex].ILOffset == (int32_t)call->gtClassProfileCandidateInfo->ilOffset); - bool is32 = m_schema[*m_currentSchemaIndex].InstrumentationKind == - ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount; - bool is64 = m_schema[*m_currentSchemaIndex].InstrumentationKind == - ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount; - assert(is32 || is64); - - // Figure out where the table is located. - // - uint8_t* classProfile = m_schema[*m_currentSchemaIndex].Offset + m_profileMemory; - *m_currentSchemaIndex += 2; // There are 2 schema entries per class probe + // Read histograms + void* typeHistogram = nullptr; + void* methodHistogram = nullptr; + + bool is32; + ReadHistogramAndAdvance(call->gtHandleHistogramProfileCandidateInfo->ilOffset, &typeHistogram, &methodHistogram, + &is32); + bool secondIs32; + ReadHistogramAndAdvance(call->gtHandleHistogramProfileCandidateInfo->ilOffset, &typeHistogram, &methodHistogram, + &secondIs32); + + assert(((typeHistogram != nullptr) || (methodHistogram != nullptr)) && + "Expected at least one handle histogram when inserting probes"); + + if ((typeHistogram != nullptr) && (methodHistogram != nullptr)) + { + // We expect both histograms to be 32-bit or 64-bit, not a mix. + assert(is32 == secondIs32); + } assert(!call->gtArgs.AreArgsComplete()); CallArg* objUse = nullptr; @@ -1576,20 +1595,57 @@ class ClassProbeInserter // Grab a temp to hold the 'this' object as it will be used three times // - unsigned const tmpNum = compiler->lvaGrabTemp(true DEBUGARG("class profile tmp")); + unsigned const tmpNum = compiler->lvaGrabTemp(true DEBUGARG("handle histogram profile tmp")); compiler->lvaTable[tmpNum].lvType = TYP_REF; + GenTree* helperCallNode = nullptr; + + if (typeHistogram != nullptr) + { + GenTree* const tmpNode = compiler->gtNewLclvNode(tmpNum, TYP_REF); + GenTree* const classProfileNode = compiler->gtNewIconNode((ssize_t)typeHistogram, TYP_I_IMPL); + helperCallNode = + compiler->gtNewHelperCallNode(is32 ? CORINFO_HELP_CLASSPROFILE32 : CORINFO_HELP_CLASSPROFILE64, + TYP_VOID, tmpNode, classProfileNode); + } + + if (methodHistogram != nullptr) + { + GenTree* const tmpNode = compiler->gtNewLclvNode(tmpNum, TYP_REF); + GenTree* const methodProfileNode = compiler->gtNewIconNode((ssize_t)methodHistogram, TYP_I_IMPL); + + GenTree* methodProfileCallNode; + if (call->IsDelegateInvoke()) + { + methodProfileCallNode = compiler->gtNewHelperCallNode(is32 ? CORINFO_HELP_DELEGATEPROFILE32 + : CORINFO_HELP_DELEGATEPROFILE64, + TYP_VOID, tmpNode, methodProfileNode); + } + else + { + assert(call->IsVirtualVtable()); + GenTree* const baseMethodNode = compiler->gtNewIconEmbMethHndNode(call->gtCallMethHnd); + methodProfileCallNode = + compiler->gtNewHelperCallNode(is32 ? CORINFO_HELP_VTABLEPROFILE32 : CORINFO_HELP_VTABLEPROFILE64, + TYP_VOID, tmpNode, baseMethodNode, methodProfileNode); + } + + if (helperCallNode == nullptr) + { + helperCallNode = methodProfileCallNode; + } + else + { + helperCallNode = compiler->gtNewOperNode(GT_COMMA, TYP_REF, helperCallNode, methodProfileCallNode); + } + } + // Generate the IR... // - GenTree* const classProfileNode = compiler->gtNewIconNode((ssize_t)classProfile, TYP_I_IMPL); - GenTree* const tmpNode = compiler->gtNewLclvNode(tmpNum, TYP_REF); - GenTreeCall* const helperCallNode = - compiler->gtNewHelperCallNode(is32 ? CORINFO_HELP_CLASSPROFILE32 : CORINFO_HELP_CLASSPROFILE64, TYP_VOID, - tmpNode, classProfileNode); GenTree* const tmpNode2 = compiler->gtNewLclvNode(tmpNum, TYP_REF); GenTree* const callCommaNode = compiler->gtNewOperNode(GT_COMMA, TYP_REF, helperCallNode, tmpNode2); GenTree* const tmpNode3 = compiler->gtNewLclvNode(tmpNum, TYP_REF); - GenTree* const asgNode = compiler->gtNewOperNode(GT_ASG, TYP_REF, tmpNode3, objUse->GetEarlyNode()); + GenTree* const asgNode = compiler->gtNewOperNode(GT_ASG, TYP_REF, tmpNode3, objUse->GetNode()); GenTree* const asgCommaNode = compiler->gtNewOperNode(GT_COMMA, TYP_REF, asgNode, callCommaNode); // Update the call @@ -1601,16 +1657,78 @@ class ClassProbeInserter m_instrCount++; } + +private: + void ReadHistogramAndAdvance(IL_OFFSET ilOffset, void** typeHistogram, void** methodHistogram, bool* histogramIs32) + { + if (*m_currentSchemaIndex >= (int)m_schema.size()) + { + return; + } + + ICorJitInfo::PgoInstrumentationSchema& countEntry = m_schema[*m_currentSchemaIndex]; + + bool is32 = countEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount; + bool is64 = countEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount; + if (!is32 && !is64) + { + return; + } + + if (countEntry.ILOffset != static_cast(ilOffset)) + { + return; + } + + assert(*m_currentSchemaIndex + 2 <= (int)m_schema.size()); + ICorJitInfo::PgoInstrumentationSchema& tableEntry = m_schema[*m_currentSchemaIndex + 1]; + assert((tableEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes) || + (tableEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods)); + + void** outHistogram; + if (tableEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes) + { + assert(*typeHistogram == nullptr); + outHistogram = typeHistogram; + } + else + { + assert(*methodHistogram == nullptr); + outHistogram = methodHistogram; + } + + *outHistogram = &m_profileMemory[countEntry.Offset]; + *histogramIs32 = is32; + +#ifdef DEBUG + if (is32) + { + ICorJitInfo::HandleHistogram32* h32 = + reinterpret_cast(&m_profileMemory[countEntry.Offset]); + assert(reinterpret_cast(&h32->Count) == &m_profileMemory[countEntry.Offset]); + assert(reinterpret_cast(h32->HandleTable) == &m_profileMemory[tableEntry.Offset]); + } + else + { + ICorJitInfo::HandleHistogram64* h64 = + reinterpret_cast(&m_profileMemory[countEntry.Offset]); + assert(reinterpret_cast(&h64->Count) == &m_profileMemory[countEntry.Offset]); + assert(reinterpret_cast(h64->HandleTable) == &m_profileMemory[tableEntry.Offset]); + } +#endif + + *m_currentSchemaIndex += 2; + } }; //------------------------------------------------------------------------ -// ClassProbeInstrumentor: instrumentor that adds a class probe to each +// HandleHistogramProbeInstrumentor: instrumentor that adds a class probe to each // virtual call in the basic block // -class ClassProbeInstrumentor : public Instrumentor +class HandleHistogramProbeInstrumentor : public Instrumentor { public: - ClassProbeInstrumentor(Compiler* comp) : Instrumentor(comp) + HandleHistogramProbeInstrumentor(Compiler* comp) : Instrumentor(comp) { } bool ShouldProcess(BasicBlock* block) override @@ -1623,13 +1741,13 @@ class ClassProbeInstrumentor : public Instrumentor }; //------------------------------------------------------------------------ -// ClassProbeInstrumentor::Prepare: prepare for class instrumentation +// HandleHistogramProbeInstrumentor::Prepare: prepare for class instrumentation // // Arguments: // preImport - true if this is the prepare call that happens before // importation // -void ClassProbeInstrumentor::Prepare(bool isPreImport) +void HandleHistogramProbeInstrumentor::Prepare(bool isPreImport) { if (isPreImport) { @@ -1641,33 +1759,33 @@ void ClassProbeInstrumentor::Prepare(bool isPreImport) // for (BasicBlock* const block : m_comp->Blocks()) { - block->bbClassSchemaIndex = -1; + block->bbHistogramSchemaIndex = -1; } #endif } //------------------------------------------------------------------------ -// ClassProbeInstrumentor::BuildSchemaElements: create schema elements for a class probe +// HandleHistogramProbeInstrumentor::BuildSchemaElements: create schema elements for a class probe // // Arguments: // block -- block to instrument // schema -- schema that we're building // -void ClassProbeInstrumentor::BuildSchemaElements(BasicBlock* block, Schema& schema) +void HandleHistogramProbeInstrumentor::BuildSchemaElements(BasicBlock* block, Schema& schema) { - if ((block->bbFlags & BBF_HAS_CLASS_PROFILE) == 0) + if ((block->bbFlags & BBF_HAS_HISTOGRAM_PROFILE) == 0) { return; } // Remember the schema index for this block. // - block->bbClassSchemaIndex = (int)schema.size(); + block->bbHistogramSchemaIndex = (int)schema.size(); // Scan the statements and identify the class probes // - BuildClassProbeSchemaGen schemaGen(schema, m_schemaCount); - ClassProbeVisitor visitor(m_comp, schemaGen); + BuildHandleHistogramProbeSchemaGen schemaGen(schema, m_schemaCount); + HandleHistogramProbeVisitor visitor(m_comp, schemaGen); for (Statement* const stmt : block->Statements()) { visitor.WalkTree(stmt->GetRootNodePointer(), nullptr); @@ -1675,16 +1793,16 @@ void ClassProbeInstrumentor::BuildSchemaElements(BasicBlock* block, Schema& sche } //------------------------------------------------------------------------ -// ClassProbeInstrumentor::Instrument: add class probes to block +// HandleHistogramProbeInstrumentor::Instrument: add class probes to block // // Arguments: // block -- block of interest // schema -- instrumentation schema // profileMemory -- profile data slab // -void ClassProbeInstrumentor::Instrument(BasicBlock* block, Schema& schema, uint8_t* profileMemory) +void HandleHistogramProbeInstrumentor::Instrument(BasicBlock* block, Schema& schema, uint8_t* profileMemory) { - if ((block->bbFlags & BBF_HAS_CLASS_PROFILE) == 0) + if ((block->bbFlags & BBF_HAS_HISTOGRAM_PROFILE) == 0) { return; } @@ -1696,11 +1814,11 @@ void ClassProbeInstrumentor::Instrument(BasicBlock* block, Schema& schema, uint8 // Scan the statements and add class probes // - int classSchemaIndex = block->bbClassSchemaIndex; - assert((classSchemaIndex >= 0) && (classSchemaIndex < (int)schema.size())); + int histogramSchemaIndex = block->bbHistogramSchemaIndex; + assert((histogramSchemaIndex >= 0) && (histogramSchemaIndex < (int)schema.size())); - ClassProbeInserter insertProbes(schema, profileMemory, &classSchemaIndex, m_instrCount); - ClassProbeVisitor visitor(m_comp, insertProbes); + HandleHistogramProbeInserter insertProbes(schema, profileMemory, &histogramSchemaIndex, m_instrCount); + HandleHistogramProbeVisitor visitor(m_comp, insertProbes); for (Statement* const stmt : block->Statements()) { visitor.WalkTree(stmt->GetRootNodePointer(), nullptr); @@ -1789,24 +1907,25 @@ PhaseStatus Compiler::fgPrepareToInstrumentMethod() // Enable class profiling by default, when jitting. // Todo: we may also want this on by default for prejitting. // - const bool useClassProfiles = (JitConfig.JitClassProfiling() > 0) && !prejit; - if (useClassProfiles) + const bool useClassProfiles = (JitConfig.JitClassProfiling() > 0); + const bool useDelegateProfiles = (JitConfig.JitDelegateProfiling() > 0); + const bool useVTableProfiles = (JitConfig.JitVTableProfiling() > 0); + if (!prejit && (useClassProfiles || useDelegateProfiles || useVTableProfiles)) { - fgClassInstrumentor = new (this, CMK_Pgo) ClassProbeInstrumentor(this); + fgHistogramInstrumentor = new (this, CMK_Pgo) HandleHistogramProbeInstrumentor(this); } else { - JITDUMP("Not doing class profiling, because %s\n", - (JitConfig.JitClassProfiling() > 0) ? "class profiles disabled" : "prejit"); + JITDUMP("Not doing class/method profiling, because %s\n", prejit ? "prejit" : "class/method profiles disabled"); - fgClassInstrumentor = new (this, CMK_Pgo) NonInstrumentor(this); + fgHistogramInstrumentor = new (this, CMK_Pgo) NonInstrumentor(this); } // Make pre-import preparations. // const bool isPreImport = true; fgCountInstrumentor->Prepare(isPreImport); - fgClassInstrumentor->Prepare(isPreImport); + fgHistogramInstrumentor->Prepare(isPreImport); return PhaseStatus::MODIFIED_NOTHING; } @@ -1835,7 +1954,7 @@ PhaseStatus Compiler::fgInstrumentMethod() // const bool isPreImport = false; fgCountInstrumentor->Prepare(isPreImport); - fgClassInstrumentor->Prepare(isPreImport); + fgHistogramInstrumentor->Prepare(isPreImport); // Walk the flow graph to build up the instrumentation schema. // @@ -1847,27 +1966,12 @@ PhaseStatus Compiler::fgInstrumentMethod() fgCountInstrumentor->BuildSchemaElements(block, schema); } - if (fgClassInstrumentor->ShouldProcess(block)) + if (fgHistogramInstrumentor->ShouldProcess(block)) { - fgClassInstrumentor->BuildSchemaElements(block, schema); + fgHistogramInstrumentor->BuildSchemaElements(block, schema); } } - // Verify we created schema for the calls needing class probes. - // (we counted those when importing) - // - // This is not true when we do partial compilation; it can/will erase class probes, - // and there's no easy way to figure out how many should be left. - // - if (doesMethodHavePartialCompilationPatchpoints()) - { - assert(fgClassInstrumentor->SchemaCount() <= info.compClassProbeCount); - } - else - { - assert(fgClassInstrumentor->SchemaCount() == info.compClassProbeCount); - } - // Optionally, when jitting, if there were no class probes and only one count probe, // suppress instrumentation. // @@ -1887,7 +1991,7 @@ PhaseStatus Compiler::fgInstrumentMethod() minimalProbeMode = (JitConfig.JitMinimalJitProfiling() > 0); } - if (minimalProbeMode && (fgCountInstrumentor->SchemaCount() == 1) && (fgClassInstrumentor->SchemaCount() == 0)) + if (minimalProbeMode && (fgCountInstrumentor->SchemaCount() == 1) && (fgHistogramInstrumentor->SchemaCount() == 0)) { JITDUMP( "Not instrumenting method: minimal probing enabled, and method has only one counter and no class probes\n"); @@ -1895,7 +1999,7 @@ PhaseStatus Compiler::fgInstrumentMethod() } JITDUMP("Instrumenting method: %d count probes and %d class probes\n", fgCountInstrumentor->SchemaCount(), - fgClassInstrumentor->SchemaCount()); + fgHistogramInstrumentor->SchemaCount()); assert(schema.size() > 0); @@ -1928,7 +2032,7 @@ PhaseStatus Compiler::fgInstrumentMethod() // Do any cleanup we might need to do... // fgCountInstrumentor->SuppressProbes(); - fgClassInstrumentor->SuppressProbes(); + fgHistogramInstrumentor->SuppressProbes(); // If we needed to create cheap preds, we're done with them now. // @@ -1939,7 +2043,7 @@ PhaseStatus Compiler::fgInstrumentMethod() // We may have modified control flow preparing for instrumentation. // - const bool modifiedFlow = fgCountInstrumentor->ModifiedFlow() || fgClassInstrumentor->ModifiedFlow(); + const bool modifiedFlow = fgCountInstrumentor->ModifiedFlow() || fgHistogramInstrumentor->ModifiedFlow(); return modifiedFlow ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } @@ -1954,22 +2058,25 @@ PhaseStatus Compiler::fgInstrumentMethod() fgCountInstrumentor->Instrument(block, schema, profileMemory); } - if (fgClassInstrumentor->ShouldProcess(block)) + if (fgHistogramInstrumentor->ShouldProcess(block)) { - fgClassInstrumentor->Instrument(block, schema, profileMemory); + fgHistogramInstrumentor->Instrument(block, schema, profileMemory); } } // Verify we instrumented everthing we created schemas for. // assert(fgCountInstrumentor->InstrCount() == fgCountInstrumentor->SchemaCount()); - assert(fgClassInstrumentor->InstrCount() == fgClassInstrumentor->SchemaCount()); + + // Verify we instrumented for each probe + // + assert(fgHistogramInstrumentor->InstrCount() == info.compHandleHistogramProbeCount); // Add any special entry instrumentation. This does not // use the schema mechanism. // fgCountInstrumentor->InstrumentMethodEntry(schema, profileMemory); - fgClassInstrumentor->InstrumentMethodEntry(schema, profileMemory); + fgHistogramInstrumentor->InstrumentMethodEntry(schema, profileMemory); // If we needed to create cheap preds, we're done with them now. // @@ -2052,6 +2159,10 @@ PhaseStatus Compiler::fgIncorporateProfileData() fgPgoClassProfiles++; break; + case ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod: + fgPgoMethodProfiles++; + break; + case ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount: case ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount: if (iSchema + 1 < fgPgoSchemaCount) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index da1bcd79595aa..33d6fab81e5ae 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -1528,7 +1528,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod() critSect = info.compCompHnd->getMethodSync(info.compMethodHnd, (void**)&pCrit); noway_assert((!critSect) != (!pCrit)); - tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL, info.compMethodHnd); + tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_GLOBAL_PTR, info.compMethodHnd); } else { @@ -3421,6 +3421,7 @@ PhaseStatus Compiler::fgDetermineFirstColdBlock() { firstColdBlock = fgFirstBB->bbNext; prevToFirstColdBlock = fgFirstBB; + JITDUMP("JitStressProcedureSplitting is enabled: Splitting after the first basic block\n"); } else { @@ -4129,47 +4130,6 @@ void Compiler::fgSetBlockOrder(BasicBlock* block) return firstNode; } -/*static*/ Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTree** pTree, fgWalkData* data) -{ - GenTree* tree = *pTree; - - // If this tree doesn't have the EXCEPT flag set, then there is no - // way any of the child nodes could throw, so we can stop recursing. - if (!(tree->gtFlags & GTF_EXCEPT)) - { - return Compiler::WALK_SKIP_SUBTREES; - } - - switch (tree->gtOper) - { - case GT_MUL: - case GT_ADD: - case GT_SUB: - case GT_CAST: - if (tree->gtOverflow()) - { - return Compiler::WALK_ABORT; - } - break; - - case GT_INDEX_ADDR: - // This calls CORINFO_HELP_RNGCHKFAIL for Debug code. - if (tree->AsIndexAddr()->IsBoundsChecked()) - { - return Compiler::WALK_ABORT; - } - break; - - case GT_BOUNDS_CHECK: - return Compiler::WALK_ABORT; - - default: - break; - } - - return Compiler::WALK_CONTINUE; -} - /*static*/ Compiler::fgWalkResult Compiler::fgChkLocAllocCB(GenTree** pTree, fgWalkData* data) { GenTree* tree = *pTree; diff --git a/src/coreclr/jit/forwardsub.cpp b/src/coreclr/jit/forwardsub.cpp index 4c3fae5f1d9f9..e6e2c84e80762 100644 --- a/src/coreclr/jit/forwardsub.cpp +++ b/src/coreclr/jit/forwardsub.cpp @@ -504,12 +504,6 @@ bool Compiler::fgForwardSubStatement(Statement* stmt) return false; } - if (gtGetStructHandleIfPresent(fwdSubNode) != gtGetStructHandleIfPresent(lhsNode)) - { - JITDUMP(" would change struct handle (assignment)\n"); - return false; - } - // If lhs is mulit-reg, rhs must be too. // if (lhsNode->IsMultiRegNode() && !fwdSubNode->IsMultiRegNode()) @@ -665,14 +659,42 @@ bool Compiler::fgForwardSubStatement(Statement* stmt) // Quirks: // - // We may sometimes lose or change a type handle. Avoid substituting if so. + // Don't substitute nodes "AddFinalArgsAndDetermineABIInfo" doesn't handle into struct args. // - if (gtGetStructHandleIfPresent(fwdSubNode) != gtGetStructHandleIfPresent(fsv.GetNode())) + if (fsv.IsCallArg() && fsv.GetNode()->TypeIs(TYP_STRUCT) && + !fwdSubNode->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD, GT_MKREFANY)) { - JITDUMP(" would change struct handle (substitution)\n"); + JITDUMP(" use is a struct arg; fwd sub node is not OBJ/LCL_VAR/LCL_FLD/MKREFANY\n"); return false; } + // We may sometimes lose or change a type handle. Avoid substituting if so. + // + // However, we allow free substitution of hardware SIMD types. + // + CORINFO_CLASS_HANDLE fwdHnd = gtGetStructHandleIfPresent(fwdSubNode); + CORINFO_CLASS_HANDLE useHnd = gtGetStructHandleIfPresent(fsv.GetNode()); + if (fwdHnd != useHnd) + { + if ((fwdHnd == NO_CLASS_HANDLE) || (useHnd == NO_CLASS_HANDLE)) + { + JITDUMP(" would add/remove struct handle (substitution)\n"); + return false; + } + +#ifdef FEATURE_SIMD + const bool bothHWSIMD = isHWSIMDClass(fwdHnd) && isHWSIMDClass(useHnd); +#else + const bool bothHWSIMD = false; +#endif + + if (!bothHWSIMD) + { + JITDUMP(" would change struct handle (substitution)\n"); + return false; + } + } + #ifdef FEATURE_SIMD // Don't forward sub a SIMD call under a HW intrinsic node. // LowerCallStruct is not prepared for this. diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index f6a167a50e139..17842a4195f02 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -567,14 +567,50 @@ void Compiler::fgWalkAllTreesPre(fgWalkPreFn* visitor, void* pCallBackData) } } +//----------------------------------------------------------- +// GetLayout: Get the struct layout for this node. +// +// Arguments: +// compiler - The Compiler instance +// +// Return Value: +// The struct layout of this node; it must have one. +// +// Notes: +// This is the "general" method for getting the layout, +// the more efficient node-specific ones should be used +// in case the node's oper is known. +// +ClassLayout* GenTree::GetLayout(Compiler* compiler) const +{ + assert(varTypeIsStruct(TypeGet())); + + switch (OperGet()) + { + case GT_LCL_VAR: + return compiler->lvaGetDesc(AsLclVar())->GetLayout(); + + case GT_LCL_FLD: + return AsLclFld()->GetLayout(); + + case GT_OBJ: + case GT_BLK: + return AsBlk()->GetLayout(); + + case GT_MKREFANY: + return compiler->typGetObjLayout(compiler->impGetRefAnyClass()); + + default: + unreached(); + } +} + //----------------------------------------------------------- // CopyReg: Copy the _gtRegNum/gtRegTag fields. // // Arguments: // from - GenTree node from which to copy // -// Return Value: -// None void GenTree::CopyReg(GenTree* from) { _gtRegNum = from->_gtRegNum; @@ -2396,7 +2432,8 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) case GT_LCL_FLD: if ((op1->AsLclFld()->GetLclNum() != op2->AsLclFld()->GetLclNum()) || - (op1->AsLclFld()->GetLclOffs() != op2->AsLclFld()->GetLclOffs())) + (op1->AsLclFld()->GetLclOffs() != op2->AsLclFld()->GetLclOffs()) || + (op1->AsLclFld()->GetLayout() != op2->AsLclFld()->GetLayout())) { break; } @@ -2792,6 +2829,7 @@ unsigned Compiler::gtHashValue(GenTree* tree) break; case GT_LCL_FLD: hash = genTreeHashAdd(hash, tree->AsLclFld()->GetLclNum()); + hash = genTreeHashAdd(hash, tree->AsLclFld()->GetLayout()); add = tree->AsLclFld()->GetLclOffs(); break; @@ -4399,6 +4437,11 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) { costSz = 10; costEx = 2; + if (con->IsIconHandle()) + { + // A sort of a hint for CSE to try harder for class handles + costEx += 1; + } } #endif // TARGET_AMD64 else @@ -4640,6 +4683,11 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree) costEx += 1; costSz += 1; } + else if (tree->TypeIs(TYP_STRUCT)) + { + costEx += IND_COST_EX; + costSz += 2; + } break; case GT_LCL_FLD_ADDR: @@ -6306,16 +6354,20 @@ bool GenTree::OperIsImplicitIndir() const } //------------------------------------------------------------------------------ -// OperMayThrow : Check whether the operation may throw. +// OperExceptions : Get exception set this tree may throw. // // // Arguments: // comp - Compiler instance // // Return Value: -// True if the given operator may cause an exception - -bool GenTree::OperMayThrow(Compiler* comp) +// A bit set of exceptions this tree may throw. +// +// Remarks: +// Should not be used on calls given that we can say nothing precise about +// those. +// +ExceptionSetFlags GenTree::OperExceptions(Compiler* comp) { GenTree* op; @@ -6332,26 +6384,40 @@ bool GenTree::OperMayThrow(Compiler* comp) if (varTypeIsFloating(op->TypeGet())) { - return false; // Floating point division does not throw. + return ExceptionSetFlags::None; } // For integers only division by 0 or by -1 can throw - if (op->IsIntegralConst() && !op->IsIntegralConst(0) && !op->IsIntegralConst(-1)) + if (op->IsIntegralConst()) { - return false; + if (op->IsIntegralConst(0)) + { + return ExceptionSetFlags::DivideByZeroException; + } + if (op->IsIntegralConst(-1)) + { + return ExceptionSetFlags::ArithmeticException; + } + + return ExceptionSetFlags::None; } - return true; + + return ExceptionSetFlags::DivideByZeroException | ExceptionSetFlags::ArithmeticException; case GT_INTRINSIC: // If this is an intrinsic that represents the object.GetType(), it can throw an NullReferenceException. // Currently, this is the only intrinsic that can throw an exception. - return AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType; + if (AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType) + { + return ExceptionSetFlags::NullReferenceException; + } + + return ExceptionSetFlags::None; case GT_CALL: + assert(!"Unexpected GT_CALL in OperExceptions"); - CorInfoHelpFunc helper; - helper = comp->eeGetHelperNum(this->AsCall()->gtCallMethHnd); - return ((helper == CORINFO_HELP_UNDEF) || !comp->s_helperCallProperties.NoThrow(helper)); + return ExceptionSetFlags::All; case GT_IND: case GT_BLK: @@ -6359,14 +6425,28 @@ bool GenTree::OperMayThrow(Compiler* comp) case GT_NULLCHECK: case GT_STORE_BLK: case GT_STORE_DYN_BLK: - return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr())); + if (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsIndir()->Addr())) + { + return ExceptionSetFlags::NullReferenceException; + } + + return ExceptionSetFlags::None; case GT_ARR_LENGTH: - return (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && - comp->fgAddrCouldBeNull(this->AsArrLen()->ArrRef())); + if (((this->gtFlags & GTF_IND_NONFAULTING) == 0) && comp->fgAddrCouldBeNull(this->AsArrLen()->ArrRef())) + { + return ExceptionSetFlags::NullReferenceException; + } + + return ExceptionSetFlags::None; case GT_ARR_ELEM: - return comp->fgAddrCouldBeNull(this->AsArrElem()->gtArrObj); + if (comp->fgAddrCouldBeNull(this->AsArrElem()->gtArrObj)) + { + return ExceptionSetFlags::NullReferenceException; + } + + return ExceptionSetFlags::None; case GT_FIELD: { @@ -6374,19 +6454,28 @@ bool GenTree::OperMayThrow(Compiler* comp) if (fldObj != nullptr) { - return comp->fgAddrCouldBeNull(fldObj); + if (comp->fgAddrCouldBeNull(fldObj)) + { + return ExceptionSetFlags::NullReferenceException; + } } - return false; + return ExceptionSetFlags::None; } case GT_BOUNDS_CHECK: + case GT_INDEX_ADDR: + return ExceptionSetFlags::IndexOutOfRangeException; + case GT_ARR_INDEX: case GT_ARR_OFFSET: - case GT_LCLHEAP: + return ExceptionSetFlags::NullReferenceException; + case GT_CKFINITE: - case GT_INDEX_ADDR: - return true; + return ExceptionSetFlags::ArithmeticException; + + case GT_LCLHEAP: + return ExceptionSetFlags::StackOverflowException; #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: @@ -6398,23 +6487,42 @@ bool GenTree::OperMayThrow(Compiler* comp) // This operation contains an implicit indirection // it could throw a null reference exception. // - return true; + return ExceptionSetFlags::NullReferenceException; } - break; + + return ExceptionSetFlags::None; } #endif // FEATURE_HW_INTRINSICS default: - break; - } + if (gtOverflowEx()) + { + return ExceptionSetFlags::OverflowException; + } - /* Overflow arithmetic operations also throw exceptions */ + return ExceptionSetFlags::None; + } +} - if (gtOverflowEx()) +//------------------------------------------------------------------------------ +// OperMayThrow : Check whether the operation may throw. +// +// +// Arguments: +// comp - Compiler instance +// +// Return Value: +// True if the given operator may cause an exception +// +bool GenTree::OperMayThrow(Compiler* comp) +{ + if (OperIs(GT_CALL)) { - return true; + CorInfoHelpFunc helper; + helper = comp->eeGetHelperNum(this->AsCall()->gtCallMethHnd); + return ((helper == CORINFO_HELP_UNDEF) || !comp->s_helperCallProperties.NoThrow(helper)); } - return false; + return OperExceptions(comp) != ExceptionSetFlags::None; } //----------------------------------------------------------------------------------- @@ -6745,8 +6853,8 @@ GenTree* Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, GenT GenTree* Compiler::gtNewIconEmbHndNode(void* value, void* pValue, GenTreeFlags iconFlags, void* compileTimeHandle) { - GenTree* iconNode; - GenTree* handleNode; + GenTreeIntCon* iconNode; + GenTree* handleNode; if (value != nullptr) { @@ -6779,7 +6887,13 @@ GenTree* Compiler::gtNewIconEmbHndNode(void* value, void* pValue, GenTreeFlags i handleNode->gtFlags |= GTF_IND_INVARIANT; } - iconNode->AsIntCon()->gtCompileTimeHandle = (size_t)compileTimeHandle; + iconNode->gtCompileTimeHandle = (size_t)compileTimeHandle; +#ifdef DEBUG + if (iconFlags == GTF_ICON_FTN_ADDR) + { + iconNode->gtTargetHandle = (size_t)compileTimeHandle; + } +#endif return handleNode; } @@ -6819,8 +6933,10 @@ GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue) tree = gtNewOperNode(GT_IND, TYP_REF, tree); // This indirection won't cause an exception. tree->gtFlags |= GTF_IND_NONFAULTING; - // This indirection points into the gloabal heap (it is String Object) - tree->gtFlags |= GTF_GLOB_REF; + // String literal objects are also ok to model as invariant. + tree->gtFlags |= GTF_IND_INVARIANT; + // ..and they are never null. + tree->gtFlags |= GTF_IND_NONNULL; break; default: @@ -9110,7 +9226,10 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) m_state = -1; return; - // Standard unary operators +// Standard unary operators +#ifdef TARGET_ARM64 + case GT_CNEG_LT: +#endif // TARGET_ARM64 case GT_STORE_LCL_VAR: case GT_STORE_LCL_FLD: case GT_NOT: @@ -16057,7 +16176,7 @@ bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call) // // Return Value: // True if so - +// bool Compiler::gtIsTypeHandleToRuntimeTypeHandleHelper(GenTreeCall* call, CorInfoHelpFunc* pHelper) { CorInfoHelpFunc helper = CORINFO_HELP_UNDEF; @@ -16084,6 +16203,61 @@ bool Compiler::gtIsActiveCSE_Candidate(GenTree* tree) return (optValnumCSE_phase && IS_CSE_INDEX(tree->gtCSEnum)); } +//------------------------------------------------------------------------ +// gtCollectExceptions: walk a tree collecting a bit set of exceptions the tree +// may throw. +// +// Arguments: +// tree - tree to examine +// +// Return Value: +// Bit set of exceptions the tree may throw. +// +ExceptionSetFlags Compiler::gtCollectExceptions(GenTree* tree) +{ + class ExceptionsWalker final : public GenTreeVisitor + { + ExceptionSetFlags m_preciseExceptions = ExceptionSetFlags::None; + + public: + ExceptionsWalker(Compiler* comp) : GenTreeVisitor(comp) + { + } + + enum + { + DoPreOrder = true, + }; + + ExceptionSetFlags GetFlags() + { + return m_preciseExceptions; + } + + fgWalkResult PreOrderVisit(GenTree** use, GenTree* user) + { + GenTree* tree = *use; + if ((tree->gtFlags & GTF_EXCEPT) == 0) + { + return WALK_SKIP_SUBTREES; + } + + m_preciseExceptions |= tree->OperExceptions(m_compiler); + return WALK_CONTINUE; + } + }; + + // We only expect the caller to ask for precise exceptions for cases where + // it may help with disambiguating between exceptions. If the tree contains + // a call it can always throw arbitrary exceptions. + assert((tree->gtFlags & GTF_CALL) == 0); + + ExceptionsWalker walker(this); + walker.WalkTree(&tree, nullptr); + assert(((tree->gtFlags & GTF_EXCEPT) == 0) || (walker.GetFlags() != ExceptionSetFlags::None)); + return walker.GetFlags(); +} + /*****************************************************************************/ struct ComplexityStruct @@ -16402,7 +16576,7 @@ const GenTreeLclVarCommon* GenTree::IsLocalAddrExpr() const // GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler) { -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) +#if FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) // TODO-LOONGARCH64-CQ: enable this. GenTreeLclVar* lcl = nullptr; @@ -16434,7 +16608,7 @@ GenTreeLclVar* GenTree::IsImplicitByrefParameterValue(Compiler* compiler) return lcl; } -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) +#endif // FEATURE_IMPLICIT_BYREFS && !defined(TARGET_LOONGARCH64) return nullptr; } @@ -17194,7 +17368,11 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) } #endif } + else #endif + { + structHnd = tree->AsLclFld()->GetLayout()->GetClassHandle(); + } break; case GT_LCL_VAR: { @@ -18402,14 +18580,16 @@ var_types GenTreeJitIntrinsic::GetSimdBaseType() const return JitType2PreciseVarType(simdBaseJitType); } -// Returns true for the SIMD Intrinsic instructions that have MemoryLoad semantics, false otherwise +//------------------------------------------------------------------------ +// OperIsMemoryLoad: Does this SIMD intrinsic have memory load semantics? +// +// Return Value: +// Whether this intrinsic may throw NullReferenceException if the +// address is "null". +// bool GenTreeSIMD::OperIsMemoryLoad() const { - if (GetSIMDIntrinsicId() == SIMDIntrinsicInitArray) - { - return true; - } - return false; + return GetSIMDIntrinsicId() == SIMDIntrinsicInitArray; } // TODO-Review: why are layouts not compared here? @@ -22408,26 +22588,56 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( /* isSimdAsHWIntrinsic */ false, op1, op2, op3); } -// Returns true for the HW Intrinsic instructions that have MemoryLoad semantics, false otherwise -bool GenTreeHWIntrinsic::OperIsMemoryLoad() const +//------------------------------------------------------------------------ +// OperIsMemoryLoad: Does this HWI node have memory load semantics? +// +// Arguments: +// pAddr - optional [out] parameter for the address +// +// Return Value: +// Whether this intrinsic may throw NullReferenceException if the +// address is "null". +// +bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const { + GenTree* addr = nullptr; + #if defined(TARGET_XARCH) || defined(TARGET_ARM64) NamedIntrinsic intrinsicId = GetHWIntrinsicId(); HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); if (category == HW_Category_MemoryLoad) { - return true; + switch (intrinsicId) + { +#ifdef TARGET_XARCH + case NI_SSE_LoadLow: + case NI_SSE_LoadHigh: + case NI_SSE2_LoadLow: + case NI_SSE2_LoadHigh: + addr = Op(2); + break; +#endif // TARGET_XARCH + +#ifdef TARGET_ARM64 + case NI_AdvSimd_LoadAndInsertScalar: + addr = Op(3); + break; +#endif // TARGET_ARM64 + + default: + addr = Op(1); + break; + } } #ifdef TARGET_XARCH - else if (HWIntrinsicInfo::MaybeMemoryLoad(GetHWIntrinsicId())) + else if (HWIntrinsicInfo::MaybeMemoryLoad(intrinsicId)) { // 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_SimpleSIMD) || (category == HW_Category_SIMDScalar)) { assert(GetOperandCount() == 1); @@ -22442,53 +22652,91 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad() const case NI_AVX2_ConvertToVector256Int16: case NI_AVX2_ConvertToVector256Int32: case NI_AVX2_ConvertToVector256Int64: - { - CorInfoType auxiliaryType = GetAuxiliaryJitType(); - - if (auxiliaryType == CORINFO_TYPE_PTR) + if (GetAuxiliaryJitType() == CORINFO_TYPE_PTR) { - return true; + addr = Op(1); } - - assert(auxiliaryType == CORINFO_TYPE_UNDEF); - return false; - } + else + { + assert(GetAuxiliaryJitType() == CORINFO_TYPE_UNDEF); + } + break; default: - { unreached(); - } } } else if (category == HW_Category_IMM) { - // Do we have less than 3 operands? - if (GetOperandCount() < 3) - { - return false; - } - else if (HWIntrinsicInfo::isAVX2GatherIntrinsic(GetHWIntrinsicId())) + switch (intrinsicId) { - return true; + case NI_AVX2_GatherVector128: + case NI_AVX2_GatherVector256: + addr = Op(1); + break; + + case NI_AVX2_GatherMaskVector128: + case NI_AVX2_GatherMaskVector256: + addr = Op(2); + break; + + default: + break; } } } #endif // TARGET_XARCH #endif // TARGET_XARCH || TARGET_ARM64 + + if (pAddr != nullptr) + { + *pAddr = addr; + } + + if (addr != nullptr) + { + assert(varTypeIsI(addr)); + return true; + } + return false; } -// Returns true for the HW Intrinsic instructions that have MemoryStore semantics, false otherwise -bool GenTreeHWIntrinsic::OperIsMemoryStore() const +//------------------------------------------------------------------------ +// OperIsMemoryLoad: Does this HWI node have memory store semantics? +// +// Arguments: +// pAddr - optional [out] parameter for the address +// +// Return Value: +// Whether this intrinsic may mutate heap state and/or throw a +// NullReferenceException if the address is "null". +// +bool GenTreeHWIntrinsic::OperIsMemoryStore(GenTree** pAddr) const { + GenTree* addr = nullptr; + #if defined(TARGET_XARCH) || defined(TARGET_ARM64) - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(GetHWIntrinsicId()); + NamedIntrinsic intrinsicId = GetHWIntrinsicId(); + HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); + if (category == HW_Category_MemoryStore) { - return true; + switch (intrinsicId) + { +#ifdef TARGET_XARCH + case NI_SSE2_MaskMove: + addr = Op(3); + break; +#endif // TARGET_XARCH + + default: + addr = Op(1); + break; + } } #ifdef TARGET_XARCH - else if (HWIntrinsicInfo::MaybeMemoryStore(GetHWIntrinsicId()) && + else if (HWIntrinsicInfo::MaybeMemoryStore(intrinsicId) && (category == HW_Category_IMM || category == HW_Category_Scalar)) { // Some intrinsics (without HW_Category_MemoryStore) also have MemoryStore semantics @@ -22499,29 +22747,44 @@ bool GenTreeHWIntrinsic::OperIsMemoryStore() const // So, the 3-argument form is MemoryStore if (GetOperandCount() == 3) { - switch (GetHWIntrinsicId()) + switch (intrinsicId) { case NI_BMI2_MultiplyNoFlags: case NI_BMI2_X64_MultiplyNoFlags: - return true; + addr = Op(3); + break; + default: - return false; + break; } } } #endif // TARGET_XARCH #endif // TARGET_XARCH || TARGET_ARM64 + + if (pAddr != nullptr) + { + *pAddr = addr; + } + + if (addr != nullptr) + { + assert(varTypeIsI(addr)); + return true; + } + return false; } -// Returns true for the HW Intrinsic instructions that have MemoryLoad or MemoryStore semantics, false otherwise +//------------------------------------------------------------------------ +// OperIsMemoryLoadOrStore: Does this HWI node have memory load or store semantics? +// +// Return Value: +// Whether "this" is "OperIsMemoryLoad" or "OperIsMemoryStore". +// bool GenTreeHWIntrinsic::OperIsMemoryLoadOrStore() const { -#if defined(TARGET_XARCH) || defined(TARGET_ARM64) return OperIsMemoryLoad() || OperIsMemoryStore(); -#else - return false; -#endif } NamedIntrinsic GenTreeHWIntrinsic::GetHWIntrinsicId() const @@ -23122,7 +23385,7 @@ unsigned GenTreeHWIntrinsic::GetResultOpNumForFMA(GenTree* use, GenTree* op1, Ge unsigned GenTreeLclFld::GetSize() const { - return genTypeSize(TypeGet()); + return TypeIs(TYP_STRUCT) ? GetLayout()->GetSize() : genTypeSize(TypeGet()); } #ifdef TARGET_ARM diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index b9ba82532a554..afd71a684725b 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -130,6 +130,45 @@ enum gtCallTypes : BYTE CT_COUNT // fake entry (must be last) }; +enum class ExceptionSetFlags : uint32_t +{ + None = 0x0, + OverflowException = 0x1, + DivideByZeroException = 0x2, + ArithmeticException = 0x4, + NullReferenceException = 0x8, + IndexOutOfRangeException = 0x10, + StackOverflowException = 0x20, + + All = OverflowException | DivideByZeroException | ArithmeticException | NullReferenceException | + IndexOutOfRangeException | StackOverflowException, +}; + +inline constexpr ExceptionSetFlags operator~(ExceptionSetFlags a) +{ + return (ExceptionSetFlags)(~(uint32_t)a); +} + +inline constexpr ExceptionSetFlags operator|(ExceptionSetFlags a, ExceptionSetFlags b) +{ + return (ExceptionSetFlags)((uint32_t)a | (uint32_t)b); +} + +inline constexpr ExceptionSetFlags operator&(ExceptionSetFlags a, ExceptionSetFlags b) +{ + return (ExceptionSetFlags)((uint32_t)a & (uint32_t)b); +} + +inline ExceptionSetFlags& operator|=(ExceptionSetFlags& a, ExceptionSetFlags b) +{ + return a = (ExceptionSetFlags)((uint32_t)a | (uint32_t)b); +} + +inline ExceptionSetFlags& operator&=(ExceptionSetFlags& a, ExceptionSetFlags b) +{ + return a = (ExceptionSetFlags)((uint32_t)a & (uint32_t)b); +} + #ifdef DEBUG /***************************************************************************** * @@ -150,7 +189,7 @@ struct BasicBlock; enum BasicBlockFlags : unsigned __int64; struct InlineCandidateInfo; struct GuardedDevirtualizationCandidateInfo; -struct ClassProfileCandidateInfo; +struct HandleHistogramProfileCandidateInfo; struct LateDevirtualizationInfo; typedef unsigned short AssertionIndex; @@ -408,7 +447,12 @@ enum GenTreeFlags : unsigned int GTF_NOREG_AT_USE = 0x00000100, // tree node is in memory at the point of use GTF_SET_FLAGS = 0x00000200, // Requires that codegen for this node set the flags. Use gtSetFlags() to check this flag. - GTF_USE_FLAGS = 0x00000400, // Indicates that this node uses the flags bits. + +#ifdef TARGET_XARCH + GTF_DONT_EXTEND = 0x00000400, // This small-typed tree produces a value with undefined upper bits. Used on x86/x64 as a + // lowering optimization and tells the codegen to use instructions like "mov al, [addr]" + // instead of "movzx/movsx", when the user node doesn't need the upper bits. +#endif // TARGET_XARCH GTF_MAKE_CSE = 0x00000800, // Hoisted expression: try hard to make this into CSE (see optPerformHoistExpr) GTF_DONT_CSE = 0x00001000, // Don't bother CSE'ing this expr @@ -526,16 +570,9 @@ enum GenTreeFlags : unsigned int // alignment of 1 byte) GTF_IND_INVARIANT = 0x01000000, // GT_IND -- the target is invariant (a prejit indirection) GTF_IND_NONNULL = 0x00400000, // GT_IND -- the indirection never returns null (zero) -#if defined(TARGET_XARCH) - GTF_IND_DONT_EXTEND = 0x00200000, // GT_IND -- the indirection does not need to extend for small types -#endif // TARGET_XARCH GTF_IND_FLAGS = GTF_IND_VOLATILE | GTF_IND_NONFAULTING | GTF_IND_TLS_REF | GTF_IND_UNALIGNED | GTF_IND_INVARIANT | - GTF_IND_NONNULL | GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP -#if defined(TARGET_XARCH) - | GTF_IND_DONT_EXTEND -#endif // TARGET_XARCH - , + GTF_IND_NONNULL | GTF_IND_TGT_NOT_HEAP | GTF_IND_TGT_HEAP, GTF_ADDRMODE_NO_CSE = 0x80000000, // GT_ADD/GT_MUL/GT_LSH -- Do not CSE this node only, forms complex // addressing mode @@ -605,11 +642,6 @@ enum GenTreeFlags : unsigned int GTF_SIMDASHW_OP = 0x80000000, // GT_HWINTRINSIC -- Indicates that the structHandle should be gotten from gtGetStructHandleForSIMD // rather than from gtGetStructHandleForHWSIMD. - - // Flag used by assertion prop to indicate that a type is a TYP_LONG -#ifdef TARGET_64BIT - GTF_ASSERTION_PROP_LONG = 0x00000001, -#endif // TARGET_64BIT }; inline constexpr GenTreeFlags operator ~(GenTreeFlags a) @@ -764,6 +796,8 @@ struct GenTree return gtType; } + ClassLayout* GetLayout(Compiler* compiler) const; + #ifdef DEBUG genTreeOps gtOperSave; // Only used to save gtOper when we destroy a node, to aid debugging. #endif @@ -1109,6 +1143,11 @@ struct GenTree return true; } + bool IsNotGcDef() const + { + return IsIntegralConst(0) || IsLocalAddrExpr(); + } + // LIR flags // These helper methods, along with the flag values they manipulate, are defined in lir.h // @@ -1815,6 +1854,7 @@ struct GenTree bool OperRequiresCallFlag(Compiler* comp); bool OperMayThrow(Compiler* comp); + ExceptionSetFlags OperExceptions(Compiler* comp); unsigned GetScaleIndexMul(); unsigned GetScaleIndexShf(); @@ -2010,6 +2050,25 @@ struct GenTree gtFlags &= ~GTF_REVERSE_OPS; } +#if defined(TARGET_XARCH) + void SetDontExtend() + { + assert(varTypeIsSmall(TypeGet()) && OperIs(GT_IND, GT_LCL_FLD)); + gtFlags |= GTF_DONT_EXTEND; + } + + void ClearDontExtend() + { + gtFlags &= ~GTF_DONT_EXTEND; + } + + bool DontExtend() const + { + assert(varTypeIsSmall(TypeGet()) || ((gtFlags & GTF_DONT_EXTEND) == 0)); + return (gtFlags & GTF_DONT_EXTEND) != 0; + } +#endif // TARGET_XARCH + bool IsUnsigned() const { return ((gtFlags & GTF_UNSIGNED) != 0); @@ -3056,8 +3115,7 @@ struct GenTreeIntCon : public GenTreeIntConCommon FieldSeqNode* gtFieldSeq; #ifdef DEBUG - // If the value represents target address, holds the method handle to that target which is used - // to fetch target method name and display in the disassembled code. + // If the value represents target address (for a field or call), holds the handle of the field (or call). size_t gtTargetHandle = 0; #endif @@ -3677,9 +3735,10 @@ struct GenTreeLclFld : public GenTreeLclVarCommon public: GenTreeLclFld(genTreeOps oper, var_types type, unsigned lclNum, unsigned lclOffs, ClassLayout* layout = nullptr) - : GenTreeLclVarCommon(oper, type, lclNum), m_lclOffs(static_cast(lclOffs)), m_layout(layout) + : GenTreeLclVarCommon(oper, type, lclNum), m_lclOffs(static_cast(lclOffs)) { assert(lclOffs <= UINT16_MAX); + SetLayout(layout); } uint16_t GetLclOffs() const @@ -3695,6 +3754,7 @@ struct GenTreeLclFld : public GenTreeLclVarCommon ClassLayout* GetLayout() const { + assert(!TypeIs(TYP_STRUCT) || (m_layout != nullptr)); return m_layout; } @@ -4563,6 +4623,7 @@ class CallArgs void RemovedWellKnownArg(WellKnownArg arg); regNumber GetCustomRegister(Compiler* comp, CorInfoCallConvExtension cc, WellKnownArg arg); void SplitArg(CallArg* arg, unsigned numRegs, unsigned numSlots); + void SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs); public: CallArgs(); @@ -4607,7 +4668,6 @@ class CallArgs void AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call); void ArgsComplete(Compiler* comp, GenTreeCall* call); - void SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs); void EvalArgsToTemps(Compiler* comp, GenTreeCall* call); void SetNeedsTemp(CallArg* arg); bool IsNonStandard(Compiler* comp, GenTreeCall* call, CallArg* arg); @@ -5308,7 +5368,7 @@ struct GenTreeCall final : public GenTree #if defined(TARGET_ARMARCH) // For ARM architectures, we always use an indirection cell for R2R calls. - if (IsR2RRelativeIndir()) + if (IsR2RRelativeIndir() && !IsDelegateInvoke()) { return WellKnownArg::R2RIndirectionCell; } @@ -5371,7 +5431,7 @@ struct GenTreeCall final : public GenTree // gtInlineCandidateInfo is only used when inlining methods InlineCandidateInfo* gtInlineCandidateInfo; GuardedDevirtualizationCandidateInfo* gtGuardedDevirtualizationCandidateInfo; - ClassProfileCandidateInfo* gtClassProfileCandidateInfo; + HandleHistogramProfileCandidateInfo* gtHandleHistogramProfileCandidateInfo; LateDevirtualizationInfo* gtLateDevirtualizationInfo; CORINFO_GENERIC_HANDLE compileTimeHelperArgumentHandle; // Used to track type handle argument of dynamic helpers void* gtDirectCallAddress; // Used to pass direct call address between lower and codegen @@ -6069,8 +6129,7 @@ struct GenTreeSIMD : public GenTreeJitIntrinsic } #endif - bool OperIsMemoryLoad() const; // Returns true for the SIMD Intrinsic instructions that have MemoryLoad semantics, - // false otherwise + bool OperIsMemoryLoad() const; SIMDIntrinsicID GetSIMDIntrinsicId() const { @@ -6114,12 +6173,10 @@ struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic } #endif - bool OperIsMemoryLoad() const; // Returns true for the HW Intrinsic instructions that have MemoryLoad semantics, - // false otherwise - bool OperIsMemoryStore() const; // Returns true for the HW Intrinsic instructions that have MemoryStore semantics, - // false otherwise - bool OperIsMemoryLoadOrStore() const; // Returns true for the HW Intrinsic instructions that have MemoryLoad or - // MemoryStore semantics, false otherwise + bool OperIsMemoryLoad(GenTree** pAddr = nullptr) const; + bool OperIsMemoryStore(GenTree** pAddr = nullptr) const; + bool OperIsMemoryLoadOrStore() const; + bool IsSimdAsHWIntrinsic() const { return (gtFlags & GTF_SIMDASHW_OP) != 0; @@ -6764,23 +6821,6 @@ struct GenTreeIndir : public GenTreeOp return (gtFlags & GTF_IND_UNALIGNED) != 0; } -#if defined(TARGET_XARCH) - void SetDontExtend() - { - gtFlags |= GTF_IND_DONT_EXTEND; - } - - void ClearDontExtend() - { - gtFlags &= ~GTF_IND_DONT_EXTEND; - } - - bool DontExtend() const - { - return (gtFlags & GTF_IND_DONT_EXTEND) != 0; - } -#endif // TARGET_XARCH - #if DEBUGGABLE_GENTREE // Used only for GenTree::GetVtableForOper() GenTreeIndir() : GenTreeOp() @@ -7441,12 +7481,18 @@ struct GenTreePutArgStk : public GenTreeUnOp // TODO-Throughput: The following information should be obtained from the child // block node. - enum class Kind : __int8{ + enum class Kind : int8_t{ Invalid, RepInstr, PartialRepInstr, Unroll, Push, }; Kind gtPutArgStkKind; -#endif +#ifdef TARGET_XARCH +private: + uint8_t m_argLoadSizeDelta; +#endif // TARGET_XARCH +#endif // FEATURE_PUT_STRUCT_ARG_STK + +public: GenTreePutArgStk(genTreeOps oper, var_types type, GenTree* op1, @@ -7472,7 +7518,10 @@ struct GenTreePutArgStk : public GenTreeUnOp #endif // FEATURE_FASTTAILCALL #if defined(FEATURE_PUT_STRUCT_ARG_STK) , gtPutArgStkKind(Kind::Invalid) +#if defined(TARGET_XARCH) + , m_argLoadSizeDelta(UINT8_MAX) #endif +#endif // FEATURE_PUT_STRUCT_ARG_STK { } @@ -7519,6 +7568,36 @@ struct GenTreePutArgStk : public GenTreeUnOp return m_byteSize; } +#ifdef TARGET_XARCH + //------------------------------------------------------------------------ + // SetArgLoadSize: Set the optimal number of bytes to load for this argument. + // + // On XARCH, it is profitable to use wider loads when our source is a local + // variable. To not duplicate the logic between lowering, LSRA and codegen, + // we do the legality check once, in lowering, and save the result here, as + // a negative delta relative to the size of the argument with padding. + // + // Arguments: + // loadSize - The optimal number of bytes to load + // + void SetArgLoadSize(unsigned loadSize) + { + unsigned argSize = GetStackByteSize(); + assert(roundUp(loadSize, TARGET_POINTER_SIZE) == argSize); + + m_argLoadSizeDelta = static_cast(argSize - loadSize); + } + + //------------------------------------------------------------------------ + // GetArgLoadSize: Get the optimal number of bytes to load for this argument. + // + unsigned GetArgLoadSize() const + { + assert(m_argLoadSizeDelta != UINT8_MAX); + return GetStackByteSize() - m_argLoadSizeDelta; + } +#endif // TARGET_XARCH + // Return true if this is a PutArgStk of a SIMD12 struct. // This is needed because such values are re-typed to SIMD16, and the type of PutArgStk is VOID. unsigned isSIMD12() const diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index a089124825ff9..53a3618100b9e 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -219,6 +219,7 @@ GTNODE(AND_NOT , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) GTNODE(ADDEX, GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Add with sign/zero extension. GTNODE(BFIZ , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero. GTNODE(CSNEG_MI , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Conditional select, negate, minus result +GTNODE(CNEG_LT , GenTreeOp ,0,GTK_UNOP|DBK_NOTHIR) // Conditional, negate, signed less than result #endif //----------------------------------------------------------------------------- diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp index 0885892bcd630..6ad3ef37cf8f1 100644 --- a/src/coreclr/jit/hwintrinsic.cpp +++ b/src/coreclr/jit/hwintrinsic.cpp @@ -314,20 +314,35 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, return NI_Throw_PlatformNotSupportedException; } + // Special case: For Vector64/128/256 we currently don't accelerate any of the methods when + // IsHardwareAccelerated reports false. For Vector64 and Vector128 this is when the baseline + // ISA is unsupported. For Vector256 this is when AVX2 is unsupported since integer types + // can't get properly accelerated. + + if (isa == InstructionSet_Vector128) + { + if (!comp->IsBaselineSimdIsaSupported()) + { + return NI_Illegal; + } + } #if defined(TARGET_XARCH) - if ((isa == InstructionSet_Vector128) || (isa == InstructionSet_Vector256)) + else if (isa == InstructionSet_Vector256) + { + if (!comp->compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + return NI_Illegal; + } + } #elif defined(TARGET_ARM64) - if ((isa == InstructionSet_Vector64) || (isa == InstructionSet_Vector128)) -#endif + else if (isa == InstructionSet_Vector64) { if (!comp->IsBaselineSimdIsaSupported()) { - // Special case: For Vector64/128/256 we currently don't accelerate any of the methods when SSE/SSE2 - // aren't supported since IsHardwareAccelerated reports false. To simplify the importation logic we'll - // just return illegal here and let it fallback to the software path instead. return NI_Illegal; } } +#endif for (int i = 0; i < (NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); i++) { @@ -640,48 +655,15 @@ static bool isSupportedBaseType(NamedIntrinsic intrinsic, CorInfoType baseJitTyp return true; } +#ifdef DEBUG + CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsic); #ifdef TARGET_XARCH - assert((intrinsic == NI_Vector128_As) || (intrinsic == NI_Vector128_AsByte) || - (intrinsic == NI_Vector128_AsDouble) || (intrinsic == NI_Vector128_AsInt16) || - (intrinsic == NI_Vector128_AsInt32) || (intrinsic == NI_Vector128_AsInt64) || - (intrinsic == NI_Vector128_AsSByte) || (intrinsic == NI_Vector128_AsSingle) || - (intrinsic == NI_Vector128_AsUInt16) || (intrinsic == NI_Vector128_AsUInt32) || - (intrinsic == NI_Vector128_AsUInt64) || (intrinsic == NI_Vector128_get_AllBitsSet) || - (intrinsic == NI_Vector128_get_Count) || (intrinsic == NI_Vector128_get_Zero) || - (intrinsic == NI_Vector128_GetElement) || (intrinsic == NI_Vector128_WithElement) || - (intrinsic == NI_Vector128_ToScalar) || (intrinsic == NI_Vector128_ToVector256) || - (intrinsic == NI_Vector128_ToVector256Unsafe) || (intrinsic == NI_Vector256_As) || - (intrinsic == NI_Vector256_AsByte) || (intrinsic == NI_Vector256_AsDouble) || - (intrinsic == NI_Vector256_AsInt16) || (intrinsic == NI_Vector256_AsInt32) || - (intrinsic == NI_Vector256_AsInt64) || (intrinsic == NI_Vector256_AsSByte) || - (intrinsic == NI_Vector256_AsSingle) || (intrinsic == NI_Vector256_AsUInt16) || - (intrinsic == NI_Vector256_AsUInt32) || (intrinsic == NI_Vector256_AsUInt64) || - (intrinsic == NI_Vector256_get_AllBitsSet) || (intrinsic == NI_Vector256_get_Count) || - (intrinsic == NI_Vector256_get_Zero) || (intrinsic == NI_Vector256_GetElement) || - (intrinsic == NI_Vector256_WithElement) || (intrinsic == NI_Vector256_GetLower) || - (intrinsic == NI_Vector256_ToScalar)); + assert((isa == InstructionSet_Vector256) || (isa == InstructionSet_Vector128)); #endif // TARGET_XARCH #ifdef TARGET_ARM64 - assert((intrinsic == NI_Vector64_As) || (intrinsic == NI_Vector64_AsByte) || (intrinsic == NI_Vector64_AsDouble) || - (intrinsic == NI_Vector64_AsInt16) || (intrinsic == NI_Vector64_AsInt32) || - (intrinsic == NI_Vector64_AsInt64) || (intrinsic == NI_Vector64_AsSByte) || - (intrinsic == NI_Vector64_AsSingle) || (intrinsic == NI_Vector64_AsUInt16) || - (intrinsic == NI_Vector64_AsUInt32) || (intrinsic == NI_Vector64_AsUInt64) || - (intrinsic == NI_Vector64_get_AllBitsSet) || (intrinsic == NI_Vector64_get_Count) || - (intrinsic == NI_Vector64_get_Zero) || (intrinsic == NI_Vector64_GetElement) || - (intrinsic == NI_Vector64_ToScalar) || (intrinsic == NI_Vector64_ToVector128) || - (intrinsic == NI_Vector64_ToVector128Unsafe) || (intrinsic == NI_Vector64_WithElement) || - (intrinsic == NI_Vector128_As) || (intrinsic == NI_Vector128_AsByte) || - (intrinsic == NI_Vector128_AsDouble) || (intrinsic == NI_Vector128_AsInt16) || - (intrinsic == NI_Vector128_AsInt32) || (intrinsic == NI_Vector128_AsInt64) || - (intrinsic == NI_Vector128_AsSByte) || (intrinsic == NI_Vector128_AsSingle) || - (intrinsic == NI_Vector128_AsUInt16) || (intrinsic == NI_Vector128_AsUInt32) || - (intrinsic == NI_Vector128_AsUInt64) || (intrinsic == NI_Vector128_get_AllBitsSet) || - (intrinsic == NI_Vector128_get_Count) || (intrinsic == NI_Vector128_get_Zero) || - (intrinsic == NI_Vector128_GetElement) || (intrinsic == NI_Vector128_GetLower) || - (intrinsic == NI_Vector128_GetUpper) || (intrinsic == NI_Vector128_ToScalar) || - (intrinsic == NI_Vector128_WithElement)); + assert((isa == InstructionSet_Vector64) || (isa == InstructionSet_Vector128)); #endif // TARGET_ARM64 +#endif // DEBUG return false; } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 316ea1670e4ed..3c01e665ddc32 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -862,26 +862,10 @@ void Compiler::impPopCallArgs(CORINFO_SIG_INFO* sig, GenTreeCall* call) // Morph trees that aren't already OBJs or MKREFANY to be OBJs assert(ti.IsType(TI_STRUCT)); - bool forceNormalization = false; - if (varTypeIsSIMD(argNode)) - { - // We need to ensure that fgMorphArgs will use the correct struct handle to ensure proper - // ABI handling of this argument. - // Note that this can happen, for example, if we have a SIMD intrinsic that returns a SIMD type - // with a different baseType than we've seen. - // We also need to ensure an OBJ node if we have a FIELD node that might be transformed to LCL_FLD - // or a plain GT_IND. - // TODO-Cleanup: Consider whether we can eliminate all of these cases. - if ((gtGetStructHandleIfPresent(argNode) != classHnd) || argNode->OperIs(GT_FIELD)) - { - forceNormalization = true; - } - } - JITDUMP("Calling impNormStructVal on:\n"); DISPTREE(argNode); - argNode = impNormStructVal(argNode, classHnd, spillCheckLevel, forceNormalization); + argNode = impNormStructVal(argNode, classHnd, spillCheckLevel); // For SIMD types the normalization can normalize TYP_STRUCT to // e.g. TYP_SIMD16 which we keep (along with the class handle) in // the CallArgs. @@ -1404,10 +1388,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, else if (src->OperIsBlk()) { asgType = impNormStructType(structHnd); - if (src->gtOper == GT_OBJ) - { - assert(src->AsObj()->GetLayout()->GetClassHandle() == structHnd); - } + assert(ClassLayout::AreCompatible(src->AsBlk()->GetLayout(), typGetObjLayout(structHnd))); } else if (src->gtOper == GT_MKREFANY) { @@ -1650,7 +1631,7 @@ GenTree* Compiler::impGetStructAddr(GenTree* structVal, // be modified to one that is handled specially by the JIT, possibly being a candidate // for full enregistration, e.g. TYP_SIMD16. If the size of the struct is already known // call structSizeMightRepresentSIMDType to determine if this api needs to be called. - +// var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoType* pSimdBaseJitType) { assert(structHnd != NO_CLASS_HANDLE); @@ -1694,7 +1675,6 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp // structVal - the node we are going to normalize // structHnd - the class handle for the node // curLevel - the current stack level -// forceNormalization - Force the creation of an OBJ node (default is false). // // Notes: // Given struct value 'structVal', make sure it is 'canonical', that is @@ -1704,12 +1684,9 @@ var_types Compiler::impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoTyp // - a node (e.g. GT_FIELD) that will be morphed. // If the node is a CALL or RET_EXPR, a copy will be made to a new temp. // -GenTree* Compiler::impNormStructVal(GenTree* structVal, - CORINFO_CLASS_HANDLE structHnd, - unsigned curLevel, - bool forceNormalization /*=false*/) +GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel) { - assert(forceNormalization || varTypeIsStruct(structVal)); + assert(varTypeIsStruct(structVal)); assert(structHnd != NO_CLASS_HANDLE); var_types structType = structVal->TypeGet(); bool makeTemp = false; @@ -1723,27 +1700,20 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, genTreeOps oper = structVal->OperGet(); switch (oper) { - // GT_RETURN and GT_MKREFANY don't capture the handle. - case GT_RETURN: - break; + // GT_MKREFANY is supported directly by args morphing. case GT_MKREFANY: alreadyNormalized = true; break; case GT_CALL: - structVal->AsCall()->gtRetClsHnd = structHnd; - makeTemp = true; - break; - case GT_RET_EXPR: - structVal->AsRetExpr()->gtRetClsHnd = structHnd; - makeTemp = true; + makeTemp = true; break; case GT_FIELD: // Wrap it in a GT_OBJ, if needed. structVal->gtType = structType; - if ((structType == TYP_STRUCT) || forceNormalization) + if (structType == TYP_STRUCT) { structVal = gtNewObjNode(structHnd, gtNewOperNode(GT_ADDR, TYP_BYREF, structVal)); } @@ -1758,7 +1728,6 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, case GT_OBJ: case GT_BLK: - case GT_ASG: // These should already have the appropriate type. assert(structVal->gtType == structType); alreadyNormalized = true; @@ -1771,10 +1740,8 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, break; case GT_CNS_VEC: - { assert(varTypeIsSIMD(structVal) && (structVal->gtType == structType)); break; - } #ifdef FEATURE_SIMD case GT_SIMD: @@ -1817,7 +1784,7 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, #ifdef FEATURE_SIMD if (blockNode->OperIsSimdOrHWintrinsic() || blockNode->IsCnsVec()) { - parent->AsOp()->gtOp2 = impNormStructVal(blockNode, structHnd, curLevel, forceNormalization); + parent->AsOp()->gtOp2 = impNormStructVal(blockNode, structHnd, curLevel); alreadyNormalized = true; } else @@ -1852,7 +1819,7 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, } structVal->gtType = structType; - if (!alreadyNormalized || forceNormalization) + if (!alreadyNormalized) { if (makeTemp) { @@ -1865,7 +1832,7 @@ GenTree* Compiler::impNormStructVal(GenTree* structVal, structLcl = gtNewLclvNode(tmpNum, structType)->AsLclVarCommon(); structVal = structLcl; } - if ((forceNormalization || (structType == TYP_STRUCT)) && !structVal->OperIsBlk()) + if ((structType == TYP_STRUCT) && !structVal->OperIsBlk()) { // Wrap it in a GT_OBJ structVal = gtNewObjNode(structHnd, gtNewOperNode(GT_ADDR, TYP_BYREF, structVal)); @@ -1938,8 +1905,8 @@ GenTree* Compiler::impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, } // Generate the full lookup tree. May be null if we're abandoning an inline attempt. - GenTree* result = impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token), - embedInfo.compileTimeHandle); + GenTreeFlags handleType = importParent ? GTF_ICON_CLASS_HDL : gtTokenToIconFlags(pResolvedToken->token); + GenTree* result = impLookupToTree(pResolvedToken, &embedInfo.lookup, handleType, embedInfo.compileTimeHandle); // If we have a result and it requires runtime lookup, wrap it in a runtime lookup node. if ((result != nullptr) && embedInfo.lookup.lookupKind.needsRuntimeLookup) @@ -8853,9 +8820,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT // Create the address node. GenTreeFlags handleKind = isBoxedStatic ? GTF_ICON_STATIC_BOX_PTR : GTF_ICON_STATIC_HDL; op1 = gtNewIconHandleNode((size_t)fldAddr, handleKind, innerFldSeq); -#ifdef DEBUG - op1->AsIntCon()->gtTargetHandle = op1->AsIntCon()->gtIconVal; -#endif + INDEBUG(op1->AsIntCon()->gtTargetHandle = reinterpret_cast(pResolvedToken->hField)); if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_INITCLASS) { @@ -10082,11 +10047,23 @@ var_types Compiler::impImportCall(OPCODE opcode, call->gtFlags |= obj->gtFlags & GTF_GLOB_EFFECT; call->AsCall()->gtArgs.PushFront(this, NewCallArg::Primitive(obj).WellKnown(WellKnownArg::ThisPointer)); - // Is this a virtual or interface call? + if (impIsThis(obj)) + { + call->AsCall()->gtCallMoreFlags |= GTF_CALL_M_NONVIRT_SAME_THIS; + } + } + + bool probing; + probing = impConsiderCallProbe(call->AsCall(), rawILOffset); + + // See if we can devirt if we aren't probing. + if (!probing && opts.OptimizationEnabled()) + { if (call->AsCall()->IsVirtual()) { // only true object pointers can be virtual - assert(obj->gtType == TYP_REF); + assert(call->AsCall()->gtArgs.HasThisPointer() && + call->AsCall()->gtArgs.GetThisArg()->GetNode()->TypeIs(TYP_REF)); // See if we can devirtualize. @@ -10102,10 +10079,10 @@ var_types Compiler::impImportCall(OPCODE opcode, // methHnd = callInfo->hMethod; } - - if (impIsThis(obj)) + else if (call->AsCall()->IsDelegateInvoke()) { - call->AsCall()->gtCallMoreFlags |= GTF_CALL_M_NONVIRT_SAME_THIS; + considerGuardedDevirtualization(call->AsCall(), rawILOffset, false, NO_METHOD_HANDLE, NO_CLASS_HANDLE, + nullptr); } } @@ -10542,7 +10519,7 @@ var_types Compiler::impImportCall(OPCODE opcode, // important devirtualizations, we'll want to allow both a class probe and a captured context. // if (origCall->IsVirtual() && (origCall->gtCallType != CT_INDIRECT) && (exactContextHnd != nullptr) && - (origCall->gtClassProfileCandidateInfo == nullptr)) + (origCall->gtHandleHistogramProfileCandidateInfo == nullptr)) { JITDUMP("\nSaving context %p for call [%06u]\n", exactContextHnd, dspTreeID(origCall)); origCall->gtCallMoreFlags |= GTF_CALL_M_HAS_LATE_DEVIRT_INFO; @@ -12152,38 +12129,31 @@ GenTree* Compiler::impCastClassOrIsInstToTree( // Check if this cast helper have some profile data if (impIsCastHelperMayHaveProfileData(helper)) { - bool doRandomDevirt = false; - const int maxLikelyClasses = 32; - int likelyClassCount = 0; - LikelyClassRecord likelyClasses[maxLikelyClasses]; -#ifdef DEBUG - // Optional stress mode to pick a random known class, rather than - // the most likely known class. - doRandomDevirt = JitConfig.JitRandomGuardedDevirtualization() != 0; + const int maxLikelyClasses = 32; + LikelyClassMethodRecord likelyClasses[maxLikelyClasses]; + unsigned likelyClassCount = + getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset); - if (doRandomDevirt) + if (likelyClassCount > 0) { - // Reuse the random inliner's random state. - CLRRandom* const random = - impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomGuardedDevirtualization()); - likelyClasses[0].clsHandle = getRandomClass(fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset, random); - likelyClasses[0].likelihood = 100; - if (likelyClasses[0].clsHandle != NO_CLASS_HANDLE) +#ifdef DEBUG + // Optional stress mode to pick a random known class, rather than + // the most likely known class. + if (JitConfig.JitRandomGuardedDevirtualization() != 0) { - likelyClassCount = 1; + // Reuse the random inliner's random state. + CLRRandom* const random = + impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomGuardedDevirtualization()); + + unsigned index = static_cast(random->Next(static_cast(likelyClassCount))); + likelyClasses[0].handle = likelyClasses[index].handle; + likelyClasses[0].likelihood = 100; + likelyClassCount = 1; } - } - else #endif - { - likelyClassCount = getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, - fgPgoData, ilOffset); - } - if (likelyClassCount > 0) - { - LikelyClassRecord likelyClass = likelyClasses[0]; - CORINFO_CLASS_HANDLE likelyCls = likelyClass.clsHandle; + LikelyClassMethodRecord likelyClass = likelyClasses[0]; + CORINFO_CLASS_HANDLE likelyCls = (CORINFO_CLASS_HANDLE)likelyClass.handle; if ((likelyCls != NO_CLASS_HANDLE) && (likelyClass.likelihood > (UINT32)JitConfig.JitGuardedDevirtualizationChainLikelihood())) @@ -12218,13 +12188,14 @@ GenTree* Compiler::impCastClassOrIsInstToTree( op2->gtFlags |= GTF_DONT_CSE; GenTreeCall* call = gtNewHelperCallNode(helper, TYP_REF, op2, op1); - if (impIsCastHelperEligibleForClassProbe(call) && !impIsClassExact(pResolvedToken->hClass)) + if ((JitConfig.JitClassProfiling() > 0) && impIsCastHelperEligibleForClassProbe(call) && + !impIsClassExact(pResolvedToken->hClass)) { - ClassProfileCandidateInfo* pInfo = new (this, CMK_Inlining) ClassProfileCandidateInfo; - pInfo->ilOffset = ilOffset; - pInfo->probeIndex = info.compClassProbeCount++; - call->gtClassProfileCandidateInfo = pInfo; - compCurBB->bbFlags |= BBF_HAS_CLASS_PROFILE; + HandleHistogramProfileCandidateInfo* pInfo = new (this, CMK_Inlining) HandleHistogramProfileCandidateInfo; + pInfo->ilOffset = ilOffset; + pInfo->probeIndex = info.compHandleHistogramProbeCount++; + call->gtHandleHistogramProfileCandidateInfo = pInfo; + compCurBB->bbFlags |= BBF_HAS_HISTOGRAM_PROFILE; } return call; } @@ -19907,8 +19878,8 @@ void Compiler::impCheckCanInline(GenTreeCall* call, if (pParam->result->IsFailure()) { - // Make sure not to report this one. It was already reported by the VM. - pParam->result->SetReported(); + // Do not report this as a failure. Instead report as a "VM failure" + pParam->result->SetVMFailure(); goto _exit; } @@ -21016,7 +20987,7 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, // Delegate Invoke method doesn't have a body and gets special cased instead. // Don't even bother trying to inline it. - if (call->IsDelegateInvoke()) + if (call->IsDelegateInvoke() && !call->IsGuardedDevirtualizationCandidate()) { inlineResult.NoteFatal(InlineObservation::CALLEE_HAS_NO_BODY); return; @@ -21201,7 +21172,7 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, // Since we're not actually inlining yet, and this call site is // still just an inline candidate, there's nothing to report. - inlineResult.SetReported(); + inlineResult.SetSuccessResult(INLINE_CHECK_CAN_INLINE_SUCCESS); } /******************************************************************************/ @@ -21401,51 +21372,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // This should be a virtual vtable or virtual stub call. // assert(call->IsVirtual()); - - // Possibly instrument. Note for OSR+PGO we will instrument when - // optimizing and (currently) won't devirtualize. We may want - // to revisit -- if we can devirtualize we should be able to - // suppress the probe. - // - // We strip BBINSTR from inlinees currently, so we'll only - // do this for the root method calls. - // - if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR)) - { - assert(opts.OptimizationDisabled() || opts.IsOSR()); - assert(!compIsForInlining()); - - // During importation, optionally flag this block as one that - // contains calls requiring class profiling. Ideally perhaps - // we'd just keep track of the calls themselves, so we don't - // have to search for them later. - // - if ((call->gtCallType != CT_INDIRECT) && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) && - !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && (JitConfig.JitClassProfiling() > 0) && - !isLateDevirtualization) - { - JITDUMP("\n ... marking [%06u] in " FMT_BB " for class profile instrumentation\n", dspTreeID(call), - compCurBB->bbNum); - ClassProfileCandidateInfo* pInfo = new (this, CMK_Inlining) ClassProfileCandidateInfo; - - // Record some info needed for the class profiling probe. - // - pInfo->ilOffset = ilOffset; - pInfo->probeIndex = info.compClassProbeCount++; - call->gtClassProfileCandidateInfo = pInfo; - - // Flag block as needing scrutiny - // - compCurBB->bbFlags |= BBF_HAS_CLASS_PROFILE; - } - return; - } - - // Bail if optimizations are disabled. - if (opts.OptimizationDisabled()) - { - return; - } + assert(opts.OptimizationEnabled()); #if defined(DEBUG) // Bail if devirt is disabled. @@ -21537,8 +21464,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, return; } - considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, - pContextHandle DEBUGARG(objClass) DEBUGARG("unknown")); + considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, pContextHandle); return; } @@ -21588,8 +21514,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, return; } - considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, - pContextHandle DEBUGARG(objClass) DEBUGARG(objClassName)); + considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, pContextHandle); return; } @@ -21705,8 +21630,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, return; } - considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, - pContextHandle DEBUGARG(objClass) DEBUGARG(objClassName)); + considerGuardedDevirtualization(call, ilOffset, isInterface, baseMethod, baseClass, pContextHandle); return; } @@ -21726,6 +21650,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, call->gtFlags &= ~GTF_CALL_VIRT_STUB; call->gtCallMethHnd = derivedMethod; call->gtCallType = CT_USER_FUNC; + call->gtControlExpr = nullptr; call->gtCallMoreFlags |= GTF_CALL_M_DEVIRTUALIZED; // Virtual calls include an implicit null check, which we may @@ -21767,14 +21692,14 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, if (JitConfig.JitCrossCheckDevirtualizationAndPGO() && canSensiblyCheck) { // We only can handle a single likely class for now - const int maxLikelyClasses = 1; - LikelyClassRecord likelyClasses[maxLikelyClasses]; + const int maxLikelyClasses = 1; + LikelyClassMethodRecord likelyClasses[maxLikelyClasses]; UINT32 numberOfClasses = getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset); UINT32 likelihood = likelyClasses[0].likelihood; - CORINFO_CLASS_HANDLE likelyClass = likelyClasses[0].clsHandle; + CORINFO_CLASS_HANDLE likelyClass = (CORINFO_CLASS_HANDLE)likelyClasses[0].handle; if (numberOfClasses > 0) { @@ -22065,6 +21990,117 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, #endif // FEATURE_READYTORUN } +//------------------------------------------------------------------------ +// impConsiderCallProbe: Consider whether a call should get a histogram probe +// and mark it if so. +// +// Arguments: +// call - The call +// ilOffset - The precise IL offset of the call +// +// Returns: +// True if the call was marked such that we will add a class or method probe for it. +// +bool Compiler::impConsiderCallProbe(GenTreeCall* call, IL_OFFSET ilOffset) +{ + // Possibly instrument. Note for OSR+PGO we will instrument when + // optimizing and (currently) won't devirtualize. We may want + // to revisit -- if we can devirtualize we should be able to + // suppress the probe. + // + // We strip BBINSTR from inlinees currently, so we'll only + // do this for the root method calls. + // + if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR)) + { + return false; + } + + assert(opts.OptimizationDisabled() || opts.IsOSR()); + assert(!compIsForInlining()); + + // During importation, optionally flag this block as one that + // contains calls requiring class profiling. Ideally perhaps + // we'd just keep track of the calls themselves, so we don't + // have to search for them later. + // + if (compClassifyGDVProbeType(call) == GDVProbeType::None) + { + return false; + } + + JITDUMP("\n ... marking [%06u] in " FMT_BB " for method/class profile instrumentation\n", dspTreeID(call), + compCurBB->bbNum); + HandleHistogramProfileCandidateInfo* pInfo = new (this, CMK_Inlining) HandleHistogramProfileCandidateInfo; + + // Record some info needed for the class profiling probe. + // + pInfo->ilOffset = ilOffset; + pInfo->probeIndex = info.compHandleHistogramProbeCount++; + call->gtHandleHistogramProfileCandidateInfo = pInfo; + + // Flag block as needing scrutiny + // + compCurBB->bbFlags |= BBF_HAS_HISTOGRAM_PROFILE; + return true; +} + +//------------------------------------------------------------------------ +// compClassifyGDVProbeType: +// Classify the type of GDV probe to use for a call site. +// +// Arguments: +// call - The call +// +// Returns: +// The type of probe to use. +// +Compiler::GDVProbeType Compiler::compClassifyGDVProbeType(GenTreeCall* call) +{ + if (call->gtCallType == CT_INDIRECT) + { + return GDVProbeType::None; + } + + if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) || opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) + { + return GDVProbeType::None; + } + + bool createTypeHistogram = false; + if (JitConfig.JitClassProfiling() > 0) + { + createTypeHistogram = call->IsVirtualStub() || call->IsVirtualVtable(); + + // Cast helpers may conditionally (depending on whether the class is + // exact or not) have probes. For those helpers we do not use this + // function to classify the probe type until after we have decided on + // whether we probe them or not. + createTypeHistogram = createTypeHistogram || (impIsCastHelperEligibleForClassProbe(call) && + (call->gtHandleHistogramProfileCandidateInfo != nullptr)); + } + + bool createMethodHistogram = ((JitConfig.JitDelegateProfiling() > 0) && call->IsDelegateInvoke()) || + ((JitConfig.JitVTableProfiling() > 0) && call->IsVirtualVtable()); + + if (createTypeHistogram && createMethodHistogram) + { + return GDVProbeType::MethodAndClassProfile; + } + + if (createTypeHistogram) + { + return GDVProbeType::ClassProfile; + } + + if (createMethodHistogram) + { + return GDVProbeType::MethodProfile; + } + + return GDVProbeType::None; +} + //------------------------------------------------------------------------ // impGetSpecialIntrinsicExactReturnType: Look for special cases where a call // to an intrinsic returns an exact type @@ -22075,7 +22111,6 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // Returns: // Exact class handle returned by the intrinsic call, if known. // Nullptr if not known, or not likely to lead to beneficial optimization. - CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE methodHnd) { JITDUMP("Special intrinsic: looking for exact type returned by %s\n", eeGetMethodFullName(methodHnd)); @@ -22237,153 +22272,380 @@ void Compiler::addFatPointerCandidate(GenTreeCall* call) } //------------------------------------------------------------------------ -// considerGuardedDevirtualization: see if we can profitably guess at the -// class involved in an interface or virtual call. +// pickGDV: Use profile information to pick a GDV candidate for a call site. // // Arguments: +// call - the call +// ilOffset - exact IL offset of the call +// isInterface - whether or not the call target is defined on an interface +// classGuess - [out] the class to guess for (mutually exclusive with methodGuess) +// methodGuess - [out] the method to guess for (mutually exclusive with classGuess) +// likelihood - [out] an estimate of the likelihood that the guess will succeed // -// call - potential guarded devirtualization candidate -// ilOffset - IL ofset of the call instruction -// isInterface - true if this is an interface call -// baseMethod - target method of the call -// baseClass - class that introduced the target method -// pContextHandle - context handle for the call -// objClass - class of 'this' in the call -// objClassName - name of the obj Class -// -// Notes: -// Consults with VM to see if there's a likely class at runtime, -// if so, adds a candidate for guarded devirtualization. -// -void Compiler::considerGuardedDevirtualization( - GenTreeCall* call, - IL_OFFSET ilOffset, - bool isInterface, - CORINFO_METHOD_HANDLE baseMethod, - CORINFO_CLASS_HANDLE baseClass, - CORINFO_CONTEXT_HANDLE* pContextHandle DEBUGARG(CORINFO_CLASS_HANDLE objClass) DEBUGARG(const char* objClassName)) +void Compiler::pickGDV(GenTreeCall* call, + IL_OFFSET ilOffset, + bool isInterface, + CORINFO_CLASS_HANDLE* classGuess, + CORINFO_METHOD_HANDLE* methodGuess, + unsigned* likelihood) { -#if defined(DEBUG) - const char* callKind = isInterface ? "interface" : "virtual"; -#endif + *classGuess = NO_CLASS_HANDLE; + *methodGuess = NO_METHOD_HANDLE; + *likelihood = 0; - JITDUMP("Considering guarded devirtualization at IL offset %u (0x%x)\n", ilOffset, ilOffset); + const int maxLikelyClasses = 32; + LikelyClassMethodRecord likelyClasses[maxLikelyClasses]; + unsigned numberOfClasses = 0; + if (call->IsVirtualStub() || call->IsVirtualVtable()) + { + numberOfClasses = + getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset); + } - // We currently only get likely class guesses when there is PGO data - // with class profiles. + const int maxLikelyMethods = 32; + LikelyClassMethodRecord likelyMethods[maxLikelyMethods]; + unsigned numberOfMethods = 0; + + // TODO-GDV: R2R support requires additional work to reacquire the + // entrypoint, similar to what happens at the end of impDevirtualizeCall. + // As part of supporting this we should merge the tail of + // impDevirtualizeCall and what happens in + // GuardedDevirtualizationTransformer::CreateThen for method GDV. // - if (fgPgoClassProfiles == 0) + if (!opts.IsReadyToRun() && (call->IsVirtualVtable() || call->IsDelegateInvoke())) { - JITDUMP("Not guessing for class: no class profile pgo data, or pgo disabled\n"); + numberOfMethods = + getLikelyMethods(likelyMethods, maxLikelyMethods, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset); + } + + if ((numberOfClasses < 1) && (numberOfMethods < 1)) + { + JITDUMP("No likely class or method, sorry\n"); return; } - // See if there's a likely guess for the class. - // - const unsigned likelihoodThreshold = isInterface ? 25 : 30; - unsigned likelihood = 0; - unsigned numberOfClasses = 0; +#ifdef DEBUG + if ((verbose || JitConfig.EnableExtraSuperPmiQueries()) && (numberOfClasses > 0)) + { + bool isExact; + bool isNonNull; + CallArg* thisArg = call->gtArgs.GetThisArg(); + CORINFO_CLASS_HANDLE declaredThisClsHnd = gtGetClassHandle(thisArg->GetNode(), &isExact, &isNonNull); + JITDUMP("Likely classes for call [%06u]", dspTreeID(call)); + if (declaredThisClsHnd != NO_CLASS_HANDLE) + { + const char* baseClassName = eeGetClassName(declaredThisClsHnd); + JITDUMP(" on class %p (%s)", declaredThisClsHnd, baseClassName); + } + JITDUMP("\n"); - CORINFO_CLASS_HANDLE likelyClass = NO_CLASS_HANDLE; + for (UINT32 i = 0; i < numberOfClasses; i++) + { + const char* className = eeGetClassName((CORINFO_CLASS_HANDLE)likelyClasses[i].handle); + JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, likelyClasses[i].handle, className, + likelyClasses[i].likelihood); + } + } - bool doRandomDevirt = false; + if ((verbose || JitConfig.EnableExtraSuperPmiQueries()) && (numberOfMethods > 0)) + { + assert(call->gtCallType == CT_USER_FUNC); + const char* baseMethName = eeGetMethodFullName(call->gtCallMethHnd); + JITDUMP("Likely methods for call [%06u] to method %s\n", dspTreeID(call), baseMethName); - const int maxLikelyClasses = 32; - LikelyClassRecord likelyClasses[maxLikelyClasses]; + for (UINT32 i = 0; i < numberOfMethods; i++) + { + CORINFO_CONST_LOOKUP lookup = {}; + info.compCompHnd->getFunctionFixedEntryPoint((CORINFO_METHOD_HANDLE)likelyMethods[i].handle, false, + &lookup); + + const char* methName = eeGetMethodFullName((CORINFO_METHOD_HANDLE)likelyMethods[i].handle); + switch (lookup.accessType) + { + case IAT_VALUE: + JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, lookup.addr, methName, + likelyMethods[i].likelihood); + break; + case IAT_PVALUE: + JITDUMP(" %u) [%p] (%s) [likelihood:%u%%]\n", i + 1, lookup.addr, methName, + likelyMethods[i].likelihood); + break; + case IAT_PPVALUE: + JITDUMP(" %u) [[%p]] (%s) [likelihood:%u%%]\n", i + 1, lookup.addr, methName, + likelyMethods[i].likelihood); + break; + default: + JITDUMP(" %u) %s [likelihood:%u%%]\n", i + 1, methName, likelyMethods[i].likelihood); + break; + } + } + } -#ifdef DEBUG // Optional stress mode to pick a random known class, rather than // the most likely known class. // - doRandomDevirt = JitConfig.JitRandomGuardedDevirtualization() != 0; - - if (doRandomDevirt) + if (JitConfig.JitRandomGuardedDevirtualization() != 0) { // Reuse the random inliner's random state. // CLRRandom* const random = impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomGuardedDevirtualization()); - likelyClasses[0].clsHandle = getRandomClass(fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset, random); - likelyClasses[0].likelihood = 100; - if (likelyClasses[0].clsHandle != NO_CLASS_HANDLE) + unsigned index = static_cast(random->Next(static_cast(numberOfClasses + numberOfMethods))); + if (index < numberOfClasses) { - numberOfClasses = 1; + *classGuess = (CORINFO_CLASS_HANDLE)likelyClasses[index].handle; + *likelihood = 100; + JITDUMP("Picked random class for GDV: %p (%s)\n", *classGuess, eeGetClassName(*classGuess)); + return; + } + else + { + *methodGuess = (CORINFO_METHOD_HANDLE)likelyMethods[index - numberOfClasses].handle; + *likelihood = 100; + JITDUMP("Picked random method for GDV: %p (%s)\n", *methodGuess, eeGetMethodFullName(*methodGuess)); + return; } } - else #endif + + // Prefer class guess as it is cheaper + if (numberOfClasses > 0) { - numberOfClasses = - getLikelyClasses(likelyClasses, maxLikelyClasses, fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset); + unsigned likelihoodThreshold = isInterface ? 25 : 30; + if (likelyClasses[0].likelihood >= likelihoodThreshold) + { + *classGuess = (CORINFO_CLASS_HANDLE)likelyClasses[0].handle; + *likelihood = likelyClasses[0].likelihood; + return; + } + + JITDUMP("Not guessing for class; likelihood is below %s call threshold %u\n", + isInterface ? "interface" : "virtual", likelihoodThreshold); } - // For now we only use the most popular type + if (numberOfMethods > 0) + { + unsigned likelihoodThreshold = 30; + if (likelyMethods[0].likelihood >= likelihoodThreshold) + { + *methodGuess = (CORINFO_METHOD_HANDLE)likelyMethods[0].handle; + *likelihood = likelyMethods[0].likelihood; + return; + } - likelihood = likelyClasses[0].likelihood; - likelyClass = likelyClasses[0].clsHandle; + JITDUMP("Not guessing for method; likelihood is below %s call threshold %u\n", + call->IsDelegateInvoke() ? "delegate" : "virtual", likelihoodThreshold); + } +} - if (numberOfClasses < 1) +//------------------------------------------------------------------------ +// isCompatibleMethodGDV: +// Check if devirtualizing a call node as a specified target method call is +// reasonable. +// +// Arguments: +// call - the call +// gdvTarget - the target method that we want to guess for and devirtualize to +// +// Returns: +// true if we can proceed with GDV. +// +// Notes: +// This implements a small simplified signature-compatibility check to +// verify that a guess is reasonable. The main goal here is to avoid blowing +// up the JIT on PGO data with stale GDV candidates; if they are not +// compatible in the ECMA sense then we do not expect the guard to ever pass +// at runtime, so we can get by with simplified rules here. +// +bool Compiler::isCompatibleMethodGDV(GenTreeCall* call, CORINFO_METHOD_HANDLE gdvTarget) +{ + CORINFO_SIG_INFO sig; + info.compCompHnd->getMethodSig(gdvTarget, &sig); + + CORINFO_ARG_LIST_HANDLE sigParam = sig.args; + unsigned numParams = sig.numArgs; + unsigned numArgs = 0; + for (CallArg& arg : call->gtArgs.Args()) { - JITDUMP("No likely class, sorry\n"); - return; - } + switch (arg.GetWellKnownArg()) + { + case WellKnownArg::RetBuffer: + case WellKnownArg::ThisPointer: + // Not part of signature but we still expect to see it here + continue; + case WellKnownArg::None: + break; + default: + assert(!"Unexpected well known arg to method GDV candidate"); + continue; + } + + numArgs++; + if (numArgs > numParams) + { + JITDUMP("Incompatible method GDV: call [%06u] has more arguments than signature (sig has %d parameters)\n", + dspTreeID(call), numParams); + return false; + } + + CORINFO_CLASS_HANDLE classHnd = NO_CLASS_HANDLE; + CorInfoType corType = strip(info.compCompHnd->getArgType(&sig, sigParam, &classHnd)); + var_types sigType = JITtype2varType(corType); + + if (!impCheckImplicitArgumentCoercion(sigType, arg.GetNode()->TypeGet())) + { + JITDUMP("Incompatible method GDV: arg [%06u] is type-incompatible with signature of target\n", + dspTreeID(arg.GetNode())); + return false; + } - assert(likelyClass != NO_CLASS_HANDLE); + // Best-effort check for struct compatibility here. + if (varTypeIsStruct(sigType) && (arg.GetSignatureClassHandle() != classHnd)) + { + ClassLayout* callLayout = typGetObjLayout(arg.GetSignatureClassHandle()); + ClassLayout* tarLayout = typGetObjLayout(classHnd); - // Print all likely classes - JITDUMP("%s classes for %p (%s):\n", doRandomDevirt ? "Random" : "Likely", dspPtr(objClass), objClassName) - for (UINT32 i = 0; i < numberOfClasses; i++) + if (!ClassLayout::AreCompatible(callLayout, tarLayout)) + { + JITDUMP("Incompatible method GDV: struct arg [%06u] is layout-incompatible with signature of target\n", + dspTreeID(arg.GetNode())); + return false; + } + } + + sigParam = info.compCompHnd->getArgNext(sigParam); + } + + if (numArgs < numParams) { - JITDUMP(" %u) %p (%s) [likelihood:%u%%]\n", i + 1, likelyClasses[i].clsHandle, - eeGetClassName(likelyClasses[i].clsHandle), likelyClasses[i].likelihood); + JITDUMP("Incompatible method GDV: call [%06u] has fewer arguments (%d) than signature (%d)\n", dspTreeID(call), + numArgs, numParams); + return false; } - // Todo: a more advanced heuristic using likelihood, number of - // classes, and the profile count for this block. - // - // For now we will guess if the likelihood is at least 25%/30% (intfc/virt), as studies - // have shown this transformation should pay off even if we guess wrong sometimes. + return true; +} + +//------------------------------------------------------------------------ +// considerGuardedDevirtualization: see if we can profitably guess at the +// class involved in an interface or virtual call. +// +// Arguments: +// +// call - potential guarded devirtualization candidate +// ilOffset - IL ofset of the call instruction +// baseMethod - target method of the call +// baseClass - class that introduced the target method +// pContextHandle - context handle for the call +// +// Notes: +// Consults with VM to see if there's a likely class at runtime, +// if so, adds a candidate for guarded devirtualization. +// +void Compiler::considerGuardedDevirtualization(GenTreeCall* call, + IL_OFFSET ilOffset, + bool isInterface, + CORINFO_METHOD_HANDLE baseMethod, + CORINFO_CLASS_HANDLE baseClass, + CORINFO_CONTEXT_HANDLE* pContextHandle) +{ + JITDUMP("Considering guarded devirtualization at IL offset %u (0x%x)\n", ilOffset, ilOffset); + + // We currently only get likely class guesses when there is PGO data + // with class profiles. // - if (likelihood < likelihoodThreshold) + if ((fgPgoClassProfiles == 0) && (fgPgoMethodProfiles == 0)) { - JITDUMP("Not guessing for class; likelihood is below %s call threshold %u\n", callKind, likelihoodThreshold); + JITDUMP("Not guessing for class or method: no GDV profile pgo data, or pgo disabled\n"); return; } - uint32_t const likelyClassAttribs = info.compCompHnd->getClassAttribs(likelyClass); + CORINFO_CLASS_HANDLE likelyClass; + CORINFO_METHOD_HANDLE likelyMethod; + unsigned likelihood; + pickGDV(call, ilOffset, isInterface, &likelyClass, &likelyMethod, &likelihood); - if ((likelyClassAttribs & CORINFO_FLG_ABSTRACT) != 0) + if ((likelyClass == NO_CLASS_HANDLE) && (likelyMethod == NO_METHOD_HANDLE)) { - // We may see an abstract likely class, if we have a stale profile. - // No point guessing for this. - // - JITDUMP("Not guessing for class; abstract (stale profile)\n"); return; } - // Figure out which method will be called. - // - CORINFO_DEVIRTUALIZATION_INFO dvInfo; - dvInfo.virtualMethod = baseMethod; - dvInfo.objClass = likelyClass; - dvInfo.context = *pContextHandle; - dvInfo.exactContext = *pContextHandle; - dvInfo.pResolvedTokenVirtualMethod = nullptr; + uint32_t likelyClassAttribs = 0; + if (likelyClass != NO_CLASS_HANDLE) + { + likelyClassAttribs = info.compCompHnd->getClassAttribs(likelyClass); - const bool canResolve = info.compCompHnd->resolveVirtualMethod(&dvInfo); + if ((likelyClassAttribs & CORINFO_FLG_ABSTRACT) != 0) + { + // We may see an abstract likely class, if we have a stale profile. + // No point guessing for this. + // + JITDUMP("Not guessing for class; abstract (stale profile)\n"); + return; + } - if (!canResolve) + // Figure out which method will be called. + // + CORINFO_DEVIRTUALIZATION_INFO dvInfo; + dvInfo.virtualMethod = baseMethod; + dvInfo.objClass = likelyClass; + dvInfo.context = *pContextHandle; + dvInfo.exactContext = *pContextHandle; + dvInfo.pResolvedTokenVirtualMethod = nullptr; + + const bool canResolve = info.compCompHnd->resolveVirtualMethod(&dvInfo); + + if (!canResolve) + { + JITDUMP("Can't figure out which method would be invoked, sorry\n"); + return; + } + + likelyMethod = dvInfo.devirtualizedMethod; + } + + uint32_t likelyMethodAttribs = info.compCompHnd->getMethodAttribs(likelyMethod); + + if (likelyClass == NO_CLASS_HANDLE) { - JITDUMP("Can't figure out which method would be invoked, sorry\n"); - return; + // For method GDV do a few more checks that we get for free in the + // resolve call above for class-based GDV. + if ((likelyMethodAttribs & CORINFO_FLG_STATIC) != 0) + { + assert(call->IsDelegateInvoke()); + JITDUMP("Cannot currently handle devirtualizing static delegate calls, sorry\n"); + return; + } + + // Verify that the call target and args look reasonable so that the JIT + // does not blow up during inlining/call morphing. + // + // NOTE: Once we want to support devirtualization of delegate calls to + // static methods and remove the check above we will start failing here + // for delegates pointing to static methods that have the first arg + // bound. For example: + // + // public static void E(this C c) ... + // Action a = new C().E; + // + // The delegate instance looks exactly like one pointing to an instance + // method in this case and the call will have zero args while the + // signature has 1 arg. + // + if (!isCompatibleMethodGDV(call, likelyMethod)) + { + JITDUMP("Target for method-based GDV is incompatible (stale profile?)\n"); + assert((fgPgoSource != ICorJitInfo::PgoSource::Dynamic) && "Unexpected stale profile in dynamic PGO data"); + return; + } } - CORINFO_METHOD_HANDLE likelyMethod = dvInfo.devirtualizedMethod; - JITDUMP("%s call would invoke method %s\n", callKind, eeGetMethodName(likelyMethod, nullptr)); + JITDUMP("%s call would invoke method %s\n", + isInterface ? "interface" : call->IsDelegateInvoke() ? "delegate" : "virtual", + eeGetMethodName(likelyMethod, nullptr)); // Add this as a potential candidate. // - uint32_t const likelyMethodAttribs = info.compCompHnd->getMethodAttribs(likelyMethod); addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyMethodAttribs, likelyClassAttribs, likelihood); } @@ -22416,8 +22678,8 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, unsigned classAttr, unsigned likelihood) { - // This transformation only makes sense for virtual calls - assert(call->IsVirtual()); + // This transformation only makes sense for delegate and virtual calls + assert(call->IsDelegateInvoke() || call->IsVirtual()); // Only mark calls if the feature is enabled. const bool isEnabled = JitConfig.JitEnableGuardedDevirtualization() > 0; @@ -22467,8 +22729,9 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, // We're all set, proceed with candidate creation. // - JITDUMP("Marking call [%06u] as guarded devirtualization candidate; will guess for class %s\n", dspTreeID(call), - eeGetClassName(classHandle)); + JITDUMP("Marking call [%06u] as guarded devirtualization candidate; will guess for %s %s\n", dspTreeID(call), + classHandle != NO_CLASS_HANDLE ? "class" : "method", + classHandle != NO_CLASS_HANDLE ? eeGetClassName(classHandle) : eeGetMethodFullName(methodHandle)); setMethodHasGuardedDevirtualization(); call->SetGuardedDevirtualizationCandidate(); diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index 14242b8f718b9..e3d799f734b8b 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -450,9 +450,11 @@ class IndirectCallTransformer class GuardedDevirtualizationTransformer final : public Transformer { + unsigned m_targetLclNum; + public: GuardedDevirtualizationTransformer(Compiler* compiler, BasicBlock* block, Statement* stmt) - : Transformer(compiler, block, stmt), returnTemp(BAD_VAR_NUM) + : Transformer(compiler, block, stmt), m_targetLclNum(BAD_VAR_NUM), returnTemp(BAD_VAR_NUM) { } @@ -538,23 +540,26 @@ class IndirectCallTransformer checkBlock = currBlock; checkBlock->bbJumpKind = BBJ_COND; - // Fetch method table from object arg to call. - GenTree* thisTree = compiler->gtCloneExpr(origCall->gtArgs.GetThisArg()->GetNode()); + CallArg* thisArg = origCall->gtArgs.GetThisArg(); + GenTree* thisTree = thisArg->GetNode(); // Create temp for this if the tree is costly. - if (!thisTree->IsLocal()) + if (thisTree->IsLocal()) + { + thisTree = compiler->gtCloneExpr(thisTree); + } + else { const unsigned thisTempNum = compiler->lvaGrabTemp(true DEBUGARG("guarded devirt this temp")); - // lvaSetClass(thisTempNum, ...); - GenTree* asgTree = compiler->gtNewTempAssign(thisTempNum, thisTree); - Statement* asgStmt = compiler->fgNewStmtFromTree(asgTree, stmt->GetDebugInfo()); + GenTree* asgTree = compiler->gtNewTempAssign(thisTempNum, thisTree); + Statement* asgStmt = compiler->fgNewStmtFromTree(asgTree, stmt->GetDebugInfo()); compiler->fgInsertStmtAtEnd(checkBlock, asgStmt); thisTree = compiler->gtNewLclvNode(thisTempNum, TYP_REF); // Propagate the new this to the call. Must be a new expr as the call // will live on in the else block and thisTree is used below. - origCall->gtArgs.GetThisArg()->SetEarlyNode(compiler->gtNewLclvNode(thisTempNum, TYP_REF)); + thisArg->SetEarlyNode(compiler->gtNewLclvNode(thisTempNum, TYP_REF)); } // Remember the current last statement. If we're doing a chained GDV, we'll clone/copy @@ -565,18 +570,96 @@ class IndirectCallTransformer // lastStmt = checkBlock->lastStmt(); - // Find target method table - // - GenTree* methodTable = compiler->gtNewMethodTableLookup(thisTree); - GuardedDevirtualizationCandidateInfo* guardedInfo = origCall->gtGuardedDevirtualizationCandidateInfo; - CORINFO_CLASS_HANDLE clsHnd = guardedInfo->guardedClassHandle; - GenTree* targetMethodTable = compiler->gtNewIconEmbClsHndNode(clsHnd); + GuardedDevirtualizationCandidateInfo* guardedInfo = origCall->gtGuardedDevirtualizationCandidateInfo; - // Compare and jump to else (which does the indirect call) if NOT equal - // - GenTree* methodTableCompare = compiler->gtNewOperNode(GT_NE, TYP_INT, targetMethodTable, methodTable); - GenTree* jmpTree = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, methodTableCompare); - Statement* jmpStmt = compiler->fgNewStmtFromTree(jmpTree, stmt->GetDebugInfo()); + // Create comparison. On success we will jump to do the indirect call. + GenTree* compare; + if (guardedInfo->guardedClassHandle != NO_CLASS_HANDLE) + { + // Find target method table + // + GenTree* methodTable = compiler->gtNewMethodTableLookup(thisTree); + CORINFO_CLASS_HANDLE clsHnd = guardedInfo->guardedClassHandle; + GenTree* targetMethodTable = compiler->gtNewIconEmbClsHndNode(clsHnd); + + compare = compiler->gtNewOperNode(GT_NE, TYP_INT, targetMethodTable, methodTable); + } + else + { + assert(origCall->IsVirtualVtable() || origCall->IsDelegateInvoke()); + // We reuse the target except if this is a chained GDV, in + // which case the check will be moved into the success case of + // a previous GDV and thus may not execute when we hit the cold + // path. + // TODO-GDV: Consider duplicating the store at the end of the + // cold case for the previous GDV. Then we can reuse the target + // if the second check of a chained GDV fails. + bool reuseTarget = (origCall->gtCallMoreFlags & GTF_CALL_M_GUARDED_DEVIRT_CHAIN) == 0; + if (origCall->IsVirtualVtable()) + { + GenTree* tarTree = compiler->fgExpandVirtualVtableCallTarget(origCall); + + if (reuseTarget) + { + m_targetLclNum = compiler->lvaGrabTemp(false DEBUGARG("guarded devirt call target temp")); + + GenTree* asgTree = compiler->gtNewTempAssign(m_targetLclNum, tarTree); + Statement* asgStmt = compiler->fgNewStmtFromTree(asgTree, stmt->GetDebugInfo()); + compiler->fgInsertStmtAtEnd(checkBlock, asgStmt); + + tarTree = compiler->gtNewLclvNode(m_targetLclNum, TYP_I_IMPL); + } + + CORINFO_METHOD_HANDLE methHnd = guardedInfo->guardedMethodHandle; + CORINFO_CONST_LOOKUP lookup; + compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &lookup); + + GenTree* compareTarTree = CreateTreeForLookup(methHnd, lookup); + compare = compiler->gtNewOperNode(GT_NE, TYP_INT, compareTarTree, tarTree); + } + else + { + // Reusing the call target for delegates is more + // complicated. Essentially we need to do the + // transformation done in LowerDelegateInvoke by converting + // the call to CT_INDIRECT and reusing the target address. + // We will do that transformation in CreateElse, but here + // we need to stash the target. + CLANG_FORMAT_COMMENT_ANCHOR; +#ifdef TARGET_ARM + // Not impossible to support, but would additionally + // require us to load the wrapper delegate cell when + // expanding. + reuseTarget &= (origCall->gtCallMoreFlags & GTF_CALL_M_WRAPPER_DELEGATE_INV) == 0; +#endif + + GenTree* offset = + compiler->gtNewIconNode((ssize_t)compiler->eeGetEEInfo()->offsetOfDelegateFirstTarget, + TYP_I_IMPL); + GenTree* tarTree = compiler->gtNewOperNode(GT_ADD, TYP_BYREF, thisTree, offset); + tarTree = compiler->gtNewIndir(TYP_I_IMPL, tarTree); + + if (reuseTarget) + { + m_targetLclNum = compiler->lvaGrabTemp(false DEBUGARG("guarded devirt call target temp")); + + GenTree* asgTree = compiler->gtNewTempAssign(m_targetLclNum, tarTree); + Statement* asgStmt = compiler->fgNewStmtFromTree(asgTree, stmt->GetDebugInfo()); + compiler->fgInsertStmtAtEnd(checkBlock, asgStmt); + tarTree = compiler->gtNewLclvNode(m_targetLclNum, TYP_I_IMPL); + } + + CORINFO_METHOD_HANDLE methHnd = guardedInfo->guardedMethodHandle; + CORINFO_CONST_LOOKUP lookup; + compiler->info.compCompHnd->getFunctionFixedEntryPoint(methHnd, false, &lookup); + + GenTree* compareTarTree = CreateTreeForLookup(methHnd, lookup); + compare = compiler->gtNewOperNode(GT_NE, TYP_INT, compareTarTree, tarTree); + } + } + + GenTree* jmpTree = compiler->gtNewOperNode(GT_JTRUE, TYP_VOID, compare); + Statement* jmpStmt = compiler->fgNewStmtFromTree(jmpTree, stmt->GetDebugInfo()); compiler->fgInsertStmtAtEnd(checkBlock, jmpStmt); } @@ -682,35 +765,94 @@ class IndirectCallTransformer InlineCandidateInfo* inlineInfo = origCall->gtInlineCandidateInfo; CORINFO_CLASS_HANDLE clsHnd = inlineInfo->guardedClassHandle; - // copy 'this' to temp with exact type. + // + // Copy the 'this' for the devirtualized call to a new temp. For + // class-based GDV this will allow us to set the exact type on that + // temp. For delegate GDV, this will be the actual 'this' object + // stored in the delegate. + // const unsigned thisTemp = compiler->lvaGrabTemp(false DEBUGARG("guarded devirt this exact temp")); GenTree* clonedObj = compiler->gtCloneExpr(origCall->gtArgs.GetThisArg()->GetNode()); - GenTree* assign = compiler->gtNewTempAssign(thisTemp, clonedObj); - compiler->lvaSetClass(thisTemp, clsHnd, true); + GenTree* newThisObj; + if (origCall->IsDelegateInvoke()) + { + GenTree* offset = + compiler->gtNewIconNode((ssize_t)compiler->eeGetEEInfo()->offsetOfDelegateInstance, TYP_I_IMPL); + newThisObj = compiler->gtNewOperNode(GT_ADD, TYP_BYREF, clonedObj, offset); + newThisObj = compiler->gtNewIndir(TYP_REF, newThisObj); + } + else + { + newThisObj = clonedObj; + } + GenTree* assign = compiler->gtNewTempAssign(thisTemp, newThisObj); + + if (clsHnd != NO_CLASS_HANDLE) + { + compiler->lvaSetClass(thisTemp, clsHnd, true); + } + else + { + compiler->lvaSetClass(thisTemp, + compiler->info.compCompHnd->getMethodClass(inlineInfo->guardedMethodHandle)); + } + compiler->fgNewStmtAtEnd(thenBlock, assign); - // Clone call. Note we must use the special candidate helper. + // Clone call for the devirtualized case. Note we must use the + // special candidate helper and we need to use the new 'this'. GenTreeCall* call = compiler->gtCloneCandidateCall(origCall); call->gtArgs.GetThisArg()->SetEarlyNode(compiler->gtNewLclvNode(thisTemp, TYP_REF)); call->SetIsGuarded(); JITDUMP("Direct call [%06u] in block " FMT_BB "\n", compiler->dspTreeID(call), thenBlock->bbNum); - // Then invoke impDevirtualizeCall to actually transform the call for us, - // given the original (base) method and the exact guarded class. It should succeed. - // - CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; - unsigned methodFlags = compiler->info.compCompHnd->getMethodAttribs(methodHnd); - CORINFO_CONTEXT_HANDLE context = inlineInfo->exactContextHnd; - const bool isLateDevirtualization = true; - const bool explicitTailCall = (call->AsCall()->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL) != 0; - compiler->impDevirtualizeCall(call, nullptr, &methodHnd, &methodFlags, &context, nullptr, - isLateDevirtualization, explicitTailCall); + CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; + CORINFO_CONTEXT_HANDLE context = inlineInfo->exactContextHnd; + if (clsHnd != NO_CLASS_HANDLE) + { + // Then invoke impDevirtualizeCall to actually transform the call for us, + // given the original (base) method and the exact guarded class. It should succeed. + // + unsigned methodFlags = compiler->info.compCompHnd->getMethodAttribs(methodHnd); + const bool isLateDevirtualization = true; + const bool explicitTailCall = (call->AsCall()->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL) != 0; + compiler->impDevirtualizeCall(call, nullptr, &methodHnd, &methodFlags, &context, nullptr, + isLateDevirtualization, explicitTailCall); + } + else + { + // Otherwise we know the exact method already, so just change + // the call as necessary here. + call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK; + call->gtCallMethHnd = methodHnd = inlineInfo->guardedMethodHandle; + call->gtCallType = CT_USER_FUNC; + call->gtCallMoreFlags |= GTF_CALL_M_DEVIRTUALIZED; + call->gtCallMoreFlags &= ~GTF_CALL_M_DELEGATE_INV; + // TODO-GDV: To support R2R we need to get the entry point + // here. We should unify with the tail of impDevirtualizeCall. + + if (origCall->IsVirtual()) + { + // Virtual calls include an implicit null check, which we may + // now need to make explicit. + bool isExact; + bool objIsNonNull; + compiler->gtGetClassHandle(newThisObj, &isExact, &objIsNonNull); + + if (!objIsNonNull) + { + call->gtFlags |= GTF_CALL_NULLCHECK; + } + } + + context = MAKE_METHODCONTEXT(methodHnd); + } // We know this call can devirtualize or we would not have set up GDV here. - // So impDevirtualizeCall should succeed in devirtualizing. + // So above code should succeed in devirtualizing. // - assert(!call->IsVirtual()); + assert(!call->IsVirtual() && !call->IsDelegateInvoke()); // If the devirtualizer was unable to transform the call to invoke the unboxed entry, the inline info // we set up may be invalid. We won't be able to inline anyways. So demote the call as an inline candidate. @@ -776,7 +918,7 @@ class IndirectCallTransformer } //------------------------------------------------------------------------ - // CreateElse: create else block. This executes the unaltered indirect call. + // CreateElse: create else block. This executes the original indirect call. // virtual void CreateElse() { @@ -796,6 +938,38 @@ class IndirectCallTransformer newStmt->SetRootNode(assign); } + if (m_targetLclNum != BAD_VAR_NUM) + { + if (call->IsVirtualVtable()) + { + // We already loaded the target once for the check, so reuse it from the temp. + call->gtControlExpr = compiler->gtNewLclvNode(m_targetLclNum, TYP_I_IMPL); + call->SetExpandedEarly(); + } + else if (call->IsDelegateInvoke()) + { + // Target was saved into a temp during check. We expand the + // delegate call to a CT_INDIRECT call that uses the target + // directly, somewhat similarly to LowerDelegateInvoke. + call->gtCallType = CT_INDIRECT; + call->gtCallAddr = compiler->gtNewLclvNode(m_targetLclNum, TYP_I_IMPL); + call->gtCallCookie = nullptr; + call->gtCallMoreFlags &= ~GTF_CALL_M_DELEGATE_INV; + + GenTree* thisOffset = + compiler->gtNewIconNode((ssize_t)compiler->eeGetEEInfo()->offsetOfDelegateInstance, TYP_I_IMPL); + CallArg* thisArg = call->gtArgs.GetThisArg(); + GenTree* delegateObj = thisArg->GetNode(); + + assert(delegateObj->OperIsLocal()); + GenTree* newThis = + compiler->gtNewOperNode(GT_ADD, TYP_BYREF, compiler->gtCloneExpr(delegateObj), thisOffset); + newThis = compiler->gtNewIndir(TYP_REF, newThis); + + thisArg->SetEarlyNode(newThis); + } + } + compiler->fgInsertStmtAtEnd(elseBlock, newStmt); // Set the original statement to a nop. @@ -1005,6 +1179,62 @@ class IndirectCallTransformer private: unsigned returnTemp; Statement* lastStmt; + + //------------------------------------------------------------------------ + // CreateTreeForLookup: Create a tree representing a lookup of a method address. + // + // Arguments: + // methHnd - the handle for the method the lookup is for + // lookup - lookup information for the address + // + // Returns: + // A node representing the lookup. + // + GenTree* CreateTreeForLookup(CORINFO_METHOD_HANDLE methHnd, const CORINFO_CONST_LOOKUP& lookup) + { + switch (lookup.accessType) + { + case IAT_VALUE: + { + return CreateFunctionTargetAddr(methHnd, lookup); + } + case IAT_PVALUE: + { + GenTree* tree = CreateFunctionTargetAddr(methHnd, lookup); + tree = compiler->gtNewIndir(TYP_I_IMPL, tree); + tree->gtFlags |= GTF_IND_NONFAULTING | GTF_IND_INVARIANT; + tree->gtFlags &= ~GTF_EXCEPT; + return tree; + } + case IAT_PPVALUE: + { + noway_assert(!"Unexpected IAT_PPVALUE"); + return nullptr; + } + case IAT_RELPVALUE: + { + GenTree* addr = CreateFunctionTargetAddr(methHnd, lookup); + GenTree* tree = CreateFunctionTargetAddr(methHnd, lookup); + tree = compiler->gtNewIndir(TYP_I_IMPL, tree); + tree->gtFlags |= GTF_IND_NONFAULTING | GTF_IND_INVARIANT; + tree->gtFlags &= ~GTF_EXCEPT; + tree = compiler->gtNewOperNode(GT_ADD, TYP_I_IMPL, tree, addr); + return tree; + } + default: + { + noway_assert(!"Bad accessType"); + return nullptr; + } + } + } + + GenTree* CreateFunctionTargetAddr(CORINFO_METHOD_HANDLE methHnd, const CORINFO_CONST_LOOKUP& lookup) + { + GenTree* con = compiler->gtNewIconHandleNode((size_t)lookup.addr, GTF_ICON_FTN_ADDR); + INDEBUG(con->AsIntCon()->gtTargetHandle = (size_t)methHnd); + return con; + } }; // Runtime lookup with dynamic dictionary expansion transformer, diff --git a/src/coreclr/jit/inline.cpp b/src/coreclr/jit/inline.cpp index 546eb2aa376f9..7f3c65fde97ff 100644 --- a/src/coreclr/jit/inline.cpp +++ b/src/coreclr/jit/inline.cpp @@ -643,7 +643,8 @@ void InlineContext::DumpXml(FILE* file, unsigned indent) // stmt - statement containing the call (if known) // description - string describing the context of the decision -InlineResult::InlineResult(Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description) +InlineResult::InlineResult( + Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description, bool doNotReport) : m_RootCompiler(nullptr) , m_Policy(nullptr) , m_Call(call) @@ -652,7 +653,9 @@ InlineResult::InlineResult(Compiler* compiler, GenTreeCall* call, Statement* stm , m_Callee(nullptr) , m_ImportedILSize(0) , m_Description(description) - , m_Reported(false) + , m_successResult(INLINE_PASS) + , m_DoNotReport(doNotReport) + , m_reportFailureAsVmFailure(false) { // Set the compiler instance m_RootCompiler = compiler->impInlineRoot(); @@ -683,6 +686,12 @@ InlineResult::InlineResult(Compiler* compiler, GenTreeCall* call, Statement* stm { m_Callee = m_Call->AsCall()->gtCallMethHnd; } + + if (!m_DoNotReport) + { + COMP_HANDLE comp = m_RootCompiler->info.compCompHnd; + comp->beginInlining(m_Caller, m_Callee); + } } //------------------------------------------------------------------------ @@ -701,7 +710,7 @@ InlineResult::InlineResult(Compiler* compiler, GenTreeCall* call, Statement* stm // We use the inlCallee member to track the method since logically // it is the callee here. -InlineResult::InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, const char* description) +InlineResult::InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, const char* description, bool doNotReport) : m_RootCompiler(nullptr) , m_Policy(nullptr) , m_Call(nullptr) @@ -709,7 +718,9 @@ InlineResult::InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, con , m_Caller(nullptr) , m_Callee(method) , m_Description(description) - , m_Reported(false) + , m_successResult(INLINE_PASS) + , m_DoNotReport(doNotReport) + , m_reportFailureAsVmFailure(false) { // Set the compiler instance m_RootCompiler = compiler->impInlineRoot(); @@ -717,6 +728,12 @@ InlineResult::InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, con // Set the policy const bool isPrejitRoot = true; m_Policy = InlinePolicy::GetPolicy(m_RootCompiler, isPrejitRoot); + + if (!m_DoNotReport) + { + COMP_HANDLE comp = m_RootCompiler->info.compCompHnd; + comp->beginInlining(m_Caller, m_Callee); + } } //------------------------------------------------------------------------ @@ -731,8 +748,6 @@ InlineResult::InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, con // EE. Optionally update the method attribute to NOINLINE if // observation and policy warrant. // -// All this can be suppressed if desired by calling setReported() -// before the InlineResult goes out of scope. void InlineResult::Report() { @@ -753,13 +768,13 @@ void InlineResult::Report() #endif // DEBUG // If we weren't actually inlining, user may have suppressed - // reporting via setReported(). If so, do nothing. - if (m_Reported) + // reporting. If so, do nothing. + if (m_DoNotReport) { return; } - m_Reported = true; + m_DoNotReport = true; #ifdef DEBUG const char* callee = nullptr; @@ -798,7 +813,7 @@ void InlineResult::Report() } } - if (IsDecided()) + if (IsDecided() || m_reportFailureAsVmFailure || m_successResult != INLINE_PASS) { const char* format = "INLINER: during '%s' result '%s' reason '%s'\n"; JITLOG_THIS(m_RootCompiler, (LL_INFO100000, format, m_Description, ResultString(), ReasonString())); diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index e5ec2ea3cc10e..f21a77da4fa14 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -344,11 +344,12 @@ class InlineResult public: // Construct a new InlineResult to help evaluate a // particular call for inlining. - InlineResult(Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description); + InlineResult( + Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description, bool doNotReport = false); // Construct a new InlineResult to evaluate a particular // method to see if it is inlineable. - InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, const char* description); + InlineResult(Compiler* compiler, CORINFO_METHOD_HANDLE method, const char* description, bool doNotReport = false); // Has the policy determined this inline should fail? bool IsFailure() const @@ -483,18 +484,42 @@ class InlineResult // Result that can be reported back to the runtime CorInfoInline Result() const { + if (m_reportFailureAsVmFailure) + return INLINE_CHECK_CAN_INLINE_VMFAIL; + + if (m_successResult != INLINE_PASS) + return m_successResult; + return InlGetCorInfoInlineDecision(m_Policy->GetDecision()); } // String describing the decision made const char* ResultString() const { + if (m_reportFailureAsVmFailure) + return "VM Reported !CanInline"; + + if (m_successResult == INLINE_PREJIT_SUCCESS) + return "PreJIT Success"; + + if (m_successResult == INLINE_CHECK_CAN_INLINE_SUCCESS) + return "CheckCanInline Success"; + return InlGetDecisionString(m_Policy->GetDecision()); } // String describing the reason for the decision const char* ReasonString() const { + if (m_reportFailureAsVmFailure) + return "VM Reported !CanInline"; + + if (m_successResult == INLINE_PREJIT_SUCCESS) + return "PreJIT Success"; + + if (m_successResult == INLINE_CHECK_CAN_INLINE_SUCCESS) + return "CheckCanInline Success"; + return InlGetObservationString(m_Policy->GetObservation()); } @@ -504,12 +529,15 @@ class InlineResult return m_Policy; } - // SetReported indicates that this particular result doesn't need - // to be reported back to the runtime, either because the runtime - // already knows, or we aren't actually inlining yet. - void SetReported() + // Set the code that shall be reported if the InlineResult is a success + void SetSuccessResult(CorInfoInline inlineSuccessCode) + { + m_successResult = inlineSuccessCode; + } + + void SetVMFailure() { - m_Reported = true; + m_reportFailureAsVmFailure = true; } // Get the InlineContext for this inline. @@ -544,13 +572,15 @@ class InlineResult CORINFO_METHOD_HANDLE m_Callee; unsigned m_ImportedILSize; // estimated size of imported IL const char* m_Description; - bool m_Reported; + CorInfoInline m_successResult; + bool m_DoNotReport; + bool m_reportFailureAsVmFailure; }; -// ClassProfileCandidateInfo provides information about +// HandleHistogramProfileCandidateInfo provides information about // profiling an indirect or virtual call. // -struct ClassProfileCandidateInfo +struct HandleHistogramProfileCandidateInfo { IL_OFFSET ilOffset; unsigned probeIndex; @@ -559,7 +589,7 @@ struct ClassProfileCandidateInfo // GuardedDevirtualizationCandidateInfo provides information about // a potential target of a virtual or interface call. // -struct GuardedDevirtualizationCandidateInfo : ClassProfileCandidateInfo +struct GuardedDevirtualizationCandidateInfo : HandleHistogramProfileCandidateInfo { CORINFO_CLASS_HANDLE guardedClassHandle; CORINFO_METHOD_HANDLE guardedMethodHandle; diff --git a/src/coreclr/jit/instrsxarch.h b/src/coreclr/jit/instrsxarch.h index 0a8527a6393fe..e766df67304d8 100644 --- a/src/coreclr/jit/instrsxarch.h +++ b/src/coreclr/jit/instrsxarch.h @@ -594,8 +594,8 @@ INST3(LAST_AVXVNNI_INSTRUCTION, "LAST_AVXVNNI_INSTRUCTION", IUM_WR, BAD_CODE, BA // BMI1 INST3(FIRST_BMI_INSTRUCTION, "FIRST_BMI_INSTRUCTION", IUM_WR, BAD_CODE, BAD_CODE, BAD_CODE, INS_FLAGS_None) INST3(andn, "andn", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF2), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Resets_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Logical AND NOT -INST3(blsi, "blsi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | 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(blsi, "blsi", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Writes_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Extract Lowest Set Isolated Bit +INST3(blsmsk, "blsmsk", IUM_WR, BAD_CODE, BAD_CODE, SSE38(0xF3), Resets_OF | Writes_SF | Writes_ZF | Undefined_AF | Undefined_PF | Resets_CF | INS_Flags_IsDstDstSrcAVXInstruction) // Get Mask Up to 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 diff --git a/src/coreclr/jit/jit.h b/src/coreclr/jit/jit.h index d4ea7ab0dcb91..110c079ee58c4 100644 --- a/src/coreclr/jit/jit.h +++ b/src/coreclr/jit/jit.h @@ -327,8 +327,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX typedef class ICorJitInfo* COMP_HANDLE; -const CORINFO_CLASS_HANDLE NO_CLASS_HANDLE = nullptr; -const CORINFO_FIELD_HANDLE NO_FIELD_HANDLE = nullptr; +const CORINFO_CLASS_HANDLE NO_CLASS_HANDLE = nullptr; +const CORINFO_FIELD_HANDLE NO_FIELD_HANDLE = nullptr; +const CORINFO_METHOD_HANDLE NO_METHOD_HANDLE = nullptr; /*****************************************************************************/ @@ -336,7 +337,8 @@ typedef unsigned IL_OFFSET; const IL_OFFSET BAD_IL_OFFSET = 0xffffffff; -const unsigned BAD_VAR_NUM = UINT_MAX; +const unsigned BAD_VAR_NUM = UINT_MAX; +const uint16_t BAD_LCL_OFFSET = UINT16_MAX; // Code can't be more than 2^31 in any direction. This is signed, so it should be used for anything that is // relative to something else. @@ -838,19 +840,26 @@ T dspOffset(T o) #endif // !defined(DEBUG) -struct LikelyClassRecord +struct LikelyClassMethodRecord { - CORINFO_CLASS_HANDLE clsHandle; - UINT32 likelihood; + intptr_t handle; + UINT32 likelihood; }; -extern "C" UINT32 WINAPI getLikelyClasses(LikelyClassRecord* pLikelyClasses, +extern "C" UINT32 WINAPI getLikelyClasses(LikelyClassMethodRecord* pLikelyClasses, UINT32 maxLikelyClasses, ICorJitInfo::PgoInstrumentationSchema* schema, UINT32 countSchemaItems, BYTE* pInstrumentationData, int32_t ilOffset); +extern "C" UINT32 WINAPI getLikelyMethods(LikelyClassMethodRecord* pLikelyMethods, + UINT32 maxLikelyMethods, + ICorJitInfo::PgoInstrumentationSchema* schema, + UINT32 countSchemaItems, + BYTE* pInstrumentationData, + int32_t ilOffset); + /*****************************************************************************/ #endif //_JIT_H_ /*****************************************************************************/ diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 0d701bb958ce3..9ae04f0505953 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -354,9 +354,9 @@ CONFIG_INTEGER(JitDisableSimdVN, W("JitDisableSimdVN"), 0) // Default 0, ValueNu // CONFIG_INTEGER(JitConstCSE, W("JitConstCSE"), 0) -#define CONST_CSE_ENABLE_ARM64 0 +#define CONST_CSE_ENABLE_ARM 0 #define CONST_CSE_DISABLE_ALL 1 -#define CONST_CSE_ENABLE_ARM64_NO_SHARING 2 +#define CONST_CSE_ENABLE_ARM_NO_SHARING 2 #define CONST_CSE_ENABLE_ALL 3 #define CONST_CSE_ENABLE_ALL_NO_SHARING 4 @@ -548,10 +548,12 @@ CONFIG_INTEGER(JitMinimalJitProfiling, W("JitMinimalJitProfiling"), 1) CONFIG_INTEGER(JitMinimalPrejitProfiling, W("JitMinimalPrejitProfiling"), 0) CONFIG_INTEGER(JitProfileCasts, W("JitProfileCasts"), 0) // Profile castclass/isinst -CONFIG_INTEGER(JitConsumeProfileForCasts, W("JitConsumeProfileForCasts"), 0) // Consume profile data (if any) for +CONFIG_INTEGER(JitConsumeProfileForCasts, W("JitConsumeProfileForCasts"), 1) // Consume profile data (if any) for // castclass/isinst CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1) // Profile virtual and interface calls +CONFIG_INTEGER(JitDelegateProfiling, W("JitDelegateProfiling"), 1) // Profile resolved delegate call targets +CONFIG_INTEGER(JitVTableProfiling, W("JitVTableProfiling"), 0) // Profile resolved vtable call targets CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1) // Profile edges instead of blocks CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect counts as 64-bit values. @@ -603,6 +605,8 @@ CONFIG_STRING(JitFunctionFile, W("JitFunctionFile")) // 1: disable frames that save FP/LR registers with the callee-saved registers (at the top of the frame) // 2: force all frames to use the frame types that save FP/LR registers with the callee-saved registers (at the top // of the frame) +// 3: force all frames to use the frame types that save FP/LR registers with the callee-saved registers (at the top +// of the frame) and also force using the large funclet frame variation (frame 5) if possible. CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, W("JitSaveFpLrWithCalleeSavedRegisters"), 0) #endif // defined(TARGET_ARM64) diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 25074f8827472..4ca754e9c993b 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -836,10 +836,10 @@ class LocalAddressVisitor final : public GenTreeVisitor LclVarDsc* varDsc = m_compiler->lvaGetDesc(val.LclNum()); - if (varDsc->lvPromoted || varDsc->lvIsStructField || m_compiler->lvaIsImplicitByRefLocal(val.LclNum())) + if (varDsc->lvPromoted || varDsc->lvIsStructField) { - // TODO-ADDR: For now we ignore promoted and "implicit by ref" variables, - // they require additional changes in subsequent phases. + // TODO-ADDR: For now we ignore promoted variables, they require + // additional changes in subsequent phases. return; } @@ -1017,11 +1017,10 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::None; } - if (varDsc->lvPromoted || varDsc->lvIsStructField || m_compiler->lvaIsImplicitByRefLocal(val.LclNum())) + if (varDsc->lvPromoted || varDsc->lvIsStructField) { - // TODO-ADDR: For now we ignore promoted and "implicit by ref" variables, - // they require additional changes in subsequent phases - // (e.g. fgMorphImplicitByRefArgs does not handle LCL_FLD nodes). + // TODO-ADDR: For now we ignore promoted variables, they require additional + // changes in subsequent phases. return IndirTransform::None; } @@ -1037,7 +1036,6 @@ class LocalAddressVisitor final : public GenTreeVisitor { // TODO-ADDR: Skip SIMD indirs for now, SIMD typed LCL_FLDs works most of the time // but there are exceptions - fgMorphFieldAssignToSimdSetElement for example. - // And more importantly, SIMD call args have to be wrapped in OBJ nodes currently. return IndirTransform::None; } @@ -1050,10 +1048,9 @@ class LocalAddressVisitor final : public GenTreeVisitor return IndirTransform::None; } - if ((user == nullptr) || !user->OperIs(GT_ASG, GT_RETURN)) + if ((user == nullptr) || !user->OperIs(GT_ASG, GT_CALL, GT_RETURN)) { - // TODO-ADDR: call args require extra work because currently they must - // be wrapped in OBJ nodes so we can't replace those with local nodes. + // TODO-ADDR: remove unused indirections. return IndirTransform::None; } @@ -1076,7 +1073,6 @@ class LocalAddressVisitor final : public GenTreeVisitor // enum class StructMatch { - Exact, Compatible, Partial }; @@ -1085,49 +1081,49 @@ class LocalAddressVisitor final : public GenTreeVisitor assert(varDsc->GetLayout() != nullptr); StructMatch match = StructMatch::Partial; - if (val.Offset() == 0) + if ((val.Offset() == 0) && ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout())) { - if (indirLayout->GetClassHandle() == varDsc->GetStructHnd()) - { - match = StructMatch::Exact; - } - else if (ClassLayout::AreCompatible(indirLayout, varDsc->GetLayout())) - { - match = StructMatch::Compatible; - } + match = StructMatch::Compatible; } // Current matrix of matches/users/types: // - // |------------|------|---------|---------| - // | STRUCT | CALL | ASG | RETURN | - // |------------|------|---------|---------| - // | Exact | None | LCL_VAR | LCL_VAR | - // | Compatible | None | LCL_VAR | LCL_VAR | - // | Partial | None | OBJ | LCL_FLD | - // |------------|------|---------|---------| + // |------------|---------|-------------|---------| + // | STRUCT | CALL(*) | ASG | RETURN | + // |------------|---------|-------------|---------| + // | Compatible | LCL_VAR | LCL_VAR | LCL_VAR | + // | Partial | LCL_FLD | OBJ/LCL_FLD | LCL_FLD | + // |------------|---------|-------------|---------| + // + // * - On x86/Windows x64 only. // - // |------------|------|---------|---------|----------| - // | SIMD | CALL | ASG | RETURN | HWI/SIMD | - // |------------|------|---------|---------|----------| - // | Exact | None | None | None | None | - // | Compatible | None | None | None | None | - // | Partial | None | None | None | None | - // |------------|------|---------|---------|----------| + // |------------|------|------|--------|----------| + // | SIMD | CALL | ASG | RETURN | HWI/SIMD | + // |------------|------|------|--------|----------| + // | Compatible | None | None | None | None | + // | Partial | None | None | None | None | + // |------------|------|------|--------|----------| // // TODO-ADDR: delete all the "None" entries and always // transform local nodes into LCL_VAR or LCL_FLD. - assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_RETURN)); + assert(indir->TypeIs(TYP_STRUCT) && user->OperIs(GT_ASG, GT_CALL, GT_RETURN)); *pStructLayout = indirLayout; - if ((match == StructMatch::Exact) || (match == StructMatch::Compatible)) + if (user->IsCall()) + { +#if !defined(WINDOWS_AMD64_ABI) && !defined(TARGET_X86) + return IndirTransform::None; +#endif // !defined(WINDOWS_AMD64_ABI) && !defined(TARGET_X86) + } + + if (match == StructMatch::Compatible) { return IndirTransform::LclVar; } - if (user->OperIs(GT_ASG)) + if (user->OperIs(GT_ASG) && (indir == user->AsOp()->gtGetOp1())) { return IndirTransform::ObjAddrLclFld; } diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index cc12c8a3837da..a1439c7e4bd5c 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -1494,14 +1494,14 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc, varDsc->lvOverlappingFields = StructHasOverlappingFields(cFlags); } -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) - varDsc->lvIsImplicitByRef = 0; -#elif defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS varDsc->lvIsImplicitByRef = 0; - varDsc->lvIs4Field1 = 0; - varDsc->lvIs4Field2 = 0; - varDsc->lvIsSplit = 0; -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#endif // FEATURE_IMPLICIT_BYREFS +#ifdef TARGET_LOONGARCH64 + varDsc->lvIs4Field1 = 0; + varDsc->lvIs4Field2 = 0; + varDsc->lvIsSplit = 0; +#endif // TARGET_LOONGARCH64 // Set the lvType (before this point it is TYP_UNDEF). @@ -1832,7 +1832,7 @@ bool Compiler::StructPromotionHelper::CanPromoteStructType(CORINFO_CLASS_HANDLE const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * FP_REGSIZE_BYTES; #endif // defined(TARGET_XARCH) || defined(TARGET_ARM64) #else // !FEATURE_SIMD - const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * sizeof(double); + const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * sizeof(double); #endif // !FEATURE_SIMD assert((BYTE)MaxOffset == MaxOffset); // because lvaStructFieldInfo.fldOffset is byte-sized @@ -2535,12 +2535,10 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum) compiler->compLongUsed = true; } -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) - +#if FEATURE_IMPLICIT_BYREFS // Reset the implicitByRef flag. fieldVarDsc->lvIsImplicitByRef = 0; - -#endif +#endif // FEATURE_IMPLICIT_BYREFS // Do we have a parameter that can be enregistered? // @@ -2890,6 +2888,61 @@ void Compiler::lvaSetVarDoNotEnregister(unsigned varNum DEBUGARG(DoNotEnregister #endif } +//------------------------------------------------------------------------ +// lvaIsImplicitByRefLocal: Is the local an "implicit byref" parameter? +// +// We term structs passed via pointers to shadow copies "implicit byrefs". +// They are used on Windows x64 for structs 3, 5, 6, 7, > 8 bytes in size, +// and on ARM64/LoongArch64 for structs larger than 16 bytes. +// +// They are "byrefs" because the VM sometimes uses memory allocated on the +// GC heap for the shadow copies. +// +// Arguments: +// lclNum - The local in question +// +// Return Value: +// Whether "lclNum" refers to an implicit byref. +// +bool Compiler::lvaIsImplicitByRefLocal(unsigned lclNum) const +{ +#if FEATURE_IMPLICIT_BYREFS + LclVarDsc* varDsc = lvaGetDesc(lclNum); + if (varDsc->lvIsImplicitByRef) + { + assert(varDsc->lvIsParam); + + assert(varTypeIsStruct(varDsc) || (varDsc->TypeGet() == TYP_BYREF)); + return true; + } +#endif // FEATURE_IMPLICIT_BYREFS + return false; +} + +//------------------------------------------------------------------------ +// lvaIsLocalImplicitlyAccessedByRef: Will this local be accessed indirectly? +// +// Arguments: +// lclNum - The number of local in question +// +// Return Value: +// If "lclNum" is an implicit byref parameter, or its dependently promoted +// field, "true", otherwise, "false". +// +// Notes: +// This method is only meaningful before the locals have been morphed into +// explicit indirections. +// +bool Compiler::lvaIsLocalImplicitlyAccessedByRef(unsigned lclNum) const +{ + if (lvaGetDesc(lclNum)->lvIsStructField) + { + return lvaIsImplicitByRefLocal(lvaGetDesc(lclNum)->lvParentLcl); + } + + return lvaIsImplicitByRefLocal(lclNum); +} + // Returns true if this local var is a multireg struct. // TODO-Throughput: This does a lookup on the class handle, and in the outgoing arg context // this information is already available on the CallArgABIInformation, and shouldn't need to be @@ -2951,7 +3004,7 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF; varDsc->lvType = impNormStructType(typeHnd, &simdBaseJitType); -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS // Mark implicit byref struct parameters if (varDsc->lvIsParam && !varDsc->lvIsStructField) { @@ -2964,7 +3017,7 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool varDsc->lvIsImplicitByRef = 1; } } -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#endif // FEATURE_IMPLICIT_BYREFS #if FEATURE_SIMD if (simdBaseJitType != CORINFO_TYPE_UNDEF) @@ -4181,49 +4234,57 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, /* Is this an assignment to a local variable? */ - if (op1->gtOper == GT_LCL_VAR && op2->gtType != TYP_BOOL) + if (op1->gtOper == GT_LCL_VAR) { - /* Only simple assignments allowed for booleans */ + LclVarDsc* varDsc = lvaGetDesc(op1->AsLclVarCommon()); - if (tree->gtOper != GT_ASG) + if (varDsc->lvPinned && varDsc->lvAllDefsAreNoGc) { - goto NOT_BOOL; + if (!op2->IsNotGcDef()) + { + varDsc->lvAllDefsAreNoGc = false; + } } - /* Is the RHS clearly a boolean value? */ - - switch (op2->gtOper) + if (op2->gtType != TYP_BOOL) { - unsigned lclNum; + /* Only simple assignments allowed for booleans */ - case GT_CNS_INT: + if (tree->gtOper != GT_ASG) + { + goto NOT_BOOL; + } - if (op2->AsIntCon()->gtIconVal == 0) - { - break; - } - if (op2->AsIntCon()->gtIconVal == 1) - { - break; - } + /* Is the RHS clearly a boolean value? */ - // Not 0 or 1, fall through .... - FALLTHROUGH; + switch (op2->gtOper) + { + case GT_CNS_INT: - default: + if (op2->AsIntCon()->gtIconVal == 0) + { + break; + } + if (op2->AsIntCon()->gtIconVal == 1) + { + break; + } - if (op2->OperIsCompare()) - { - break; - } + // Not 0 or 1, fall through .... + FALLTHROUGH; - NOT_BOOL: + default: - lclNum = op1->AsLclVarCommon()->GetLclNum(); - noway_assert(lclNum < lvaCount); + if (op2->OperIsCompare()) + { + break; + } - lvaTable[lclNum].lvIsBoolean = false; - break; + NOT_BOOL: + + varDsc->lvIsBoolean = false; + break; + } } } } @@ -4278,7 +4339,8 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, { if (lvaVarAddrExposed(lclNum)) { - varDsc->lvIsBoolean = false; + varDsc->lvIsBoolean = false; + varDsc->lvAllDefsAreNoGc = false; } if (tree->gtOper == GT_LCL_FLD) @@ -4750,6 +4812,8 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { varDsc->lvSingleDef = varDsc->lvIsParam; varDsc->lvSingleDefRegCandidate = varDsc->lvIsParam; + + varDsc->lvAllDefsAreNoGc = (varDsc->lvImplicitlyReferenced == false); } } @@ -4868,6 +4932,13 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) varDsc->lvImplicitlyReferenced = 1; } } + + if (varDsc->lvPinned && varDsc->lvAllDefsAreNoGc) + { + varDsc->lvPinned = 0; + + JITDUMP("V%02u was unpinned as all def candidates were local.\n", lclNum); + } } } @@ -6332,7 +6403,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() { codeGen->SetSaveFpLrWithAllCalleeSavedRegisters(false); // Disable using new frames } - else if (opts.compJitSaveFpLrWithCalleeSavedRegisters == 2) + else if ((opts.compJitSaveFpLrWithCalleeSavedRegisters == 2) || (opts.compJitSaveFpLrWithCalleeSavedRegisters == 3)) { codeGen->SetSaveFpLrWithAllCalleeSavedRegisters(true); // Force using new frames } diff --git a/src/coreclr/jit/likelyclass.cpp b/src/coreclr/jit/likelyclass.cpp index 632c9ce8b847b..6943c0c5a83a9 100644 --- a/src/coreclr/jit/likelyclass.cpp +++ b/src/coreclr/jit/likelyclass.cpp @@ -26,45 +26,45 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Data item in class profile histogram // -struct LikelyClassHistogramEntry +struct LikelyClassMethodHistogramEntry { - // Class that was observed at runtime - INT_PTR m_mt; // This may be an "unknown type handle" + // Handle that was observed at runtime + INT_PTR m_handle; // This may be an "unknown handle" // Number of observations in the table unsigned m_count; }; // Summarizes a ClassProfile table by forming a Histogram // -struct LikelyClassHistogram +struct LikelyClassMethodHistogram { - LikelyClassHistogram(INT_PTR* histogramEntries, unsigned entryCount); + LikelyClassMethodHistogram(INT_PTR* histogramEntries, unsigned entryCount); // Sum of counts from all entries in the histogram. This includes "unknown" entries which are not captured in // m_histogram unsigned m_totalCount; - // Rough guess at count of unknown types - unsigned m_unknownTypes; + // Rough guess at count of unknown handles + unsigned m_unknownHandles; // Histogram entries, in no particular order. - LikelyClassHistogramEntry m_histogram[HISTOGRAM_MAX_SIZE_COUNT]; - UINT32 countHistogramElements = 0; + LikelyClassMethodHistogramEntry m_histogram[HISTOGRAM_MAX_SIZE_COUNT]; + UINT32 countHistogramElements = 0; - LikelyClassHistogramEntry HistogramEntryAt(unsigned index) + LikelyClassMethodHistogramEntry HistogramEntryAt(unsigned index) { return m_histogram[index]; } }; //------------------------------------------------------------------------ -// LikelyClassHistogram::LikelyClassHistgram: construct a new histogram +// LikelyClassMethodHistogram::LikelyClassMethodHistgram: construct a new histogram // // Arguments: // histogramEntries - pointer to the table portion of a ClassProfile* object (see corjit.h) // entryCount - number of entries in the table to examine // -LikelyClassHistogram::LikelyClassHistogram(INT_PTR* histogramEntries, unsigned entryCount) +LikelyClassMethodHistogram::LikelyClassMethodHistogram(INT_PTR* histogramEntries, unsigned entryCount) { - m_unknownTypes = 0; + m_unknownHandles = 0; m_totalCount = 0; uint32_t unknownTypeHandleMask = 0; @@ -83,7 +83,7 @@ LikelyClassHistogram::LikelyClassHistogram(INT_PTR* histogramEntries, unsigned e unsigned h = 0; for (; h < countHistogramElements; h++) { - if (m_histogram[h].m_mt == currentEntry) + if (m_histogram[h].m_handle == currentEntry) { m_histogram[h].m_count++; found = true; @@ -97,8 +97,8 @@ LikelyClassHistogram::LikelyClassHistogram(INT_PTR* histogramEntries, unsigned e { continue; } - LikelyClassHistogramEntry newEntry; - newEntry.m_mt = currentEntry; + LikelyClassMethodHistogramEntry newEntry; + newEntry.m_handle = currentEntry; newEntry.m_count = 1; m_histogram[countHistogramElements++] = newEntry; } @@ -106,42 +106,28 @@ LikelyClassHistogram::LikelyClassHistogram(INT_PTR* histogramEntries, unsigned e } //------------------------------------------------------------------------ -// getLikelyClasses: find class profile data for an IL offset, and return the most likely classes -// -// Arguments: -// pLikelyClasses - [OUT] array of likely classes sorted by likelihood (descending). It must be -// at least of 'maxLikelyClasses' (next argument) length. -// The array consists of pairs "clsHandle - likelihood" ordered by likelihood -// (descending) where likelihood can be any value in [0..100] range. clsHandle -// is never null for [0..) range, Items in -// [..maxLikelyClasses) are zeroed if the number -// of classes seen is less than maxLikelyClasses provided. -// maxLikelyClasses - limit for likely classes to output -// schema - profile schema -// countSchemaItems - number of items in the schema -// pInstrumentationData - associated data -// ilOffset - il offset of the callvirt +// getLikelyClassesOrMethods: +// Find class/method profile data for an IL offset, and return the most +// likely classes/methods. // -// Returns: -// Estimated number of classes seen at runtime -// -// Notes: -// A "monomorphic" call site will return likelihood 100 and number of entries = 1. -// -// This is used by the devirtualization logic below, and by crossgen2 when producing -// the R2R image (to reduce the sizecost of carrying the type histogram) -// -// This code can runs without a jit instance present, so JITDUMP and related -// cannot be used. +// This is a common entrypoint for getLikelyClasses and getLikelyMethods. +// See documentation for those for more information. // -extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* pLikelyClasses, - UINT32 maxLikelyClasses, - ICorJitInfo::PgoInstrumentationSchema* schema, - UINT32 countSchemaItems, - BYTE* pInstrumentationData, - int32_t ilOffset) +static unsigned getLikelyClassesOrMethods(LikelyClassMethodRecord* pLikelyEntries, + UINT32 maxLikelyClasses, + ICorJitInfo::PgoInstrumentationSchema* schema, + UINT32 countSchemaItems, + BYTE* pInstrumentationData, + int32_t ilOffset, + bool types) { - ZeroMemory(pLikelyClasses, maxLikelyClasses * sizeof(*pLikelyClasses)); + ICorJitInfo::PgoInstrumentationKind histogramKind = + types ? ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes + : ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods; + ICorJitInfo::PgoInstrumentationKind compressedKind = types ? ICorJitInfo::PgoInstrumentationKind::GetLikelyClass + : ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod; + + memset(pLikelyEntries, 0, maxLikelyClasses * sizeof(*pLikelyEntries)); if (schema == nullptr) { @@ -153,17 +139,16 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* if (schema[i].ILOffset != ilOffset) continue; - if ((schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyClass) && - (schema[i].Count == 1)) + if ((schema[i].InstrumentationKind == compressedKind) && (schema[i].Count == 1)) { - INT_PTR result = *(INT_PTR*)(pInstrumentationData + schema[i].Offset); + intptr_t result = *(intptr_t*)(pInstrumentationData + schema[i].Offset); if (ICorJitInfo::IsUnknownHandle(result)) { return 0; } - assert(result != 0); // we don't expect zero in GetLikelyClass - pLikelyClasses[0].likelihood = (UINT32)(schema[i].Other & 0xFF); - pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)result; + assert(result != 0); // we don't expect zero in GetLikelyClass/GetLikelyMethod + pLikelyEntries[0].likelihood = (UINT32)(schema[i].Other & 0xFF); + pLikelyEntries[0].handle = result; return 1; } @@ -172,11 +157,11 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount); if (isHistogramCount && (schema[i].Count == 1) && ((i + 1) < countSchemaItems) && - (schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes)) + (schema[i + 1].InstrumentationKind == histogramKind)) { // Form a histogram // - LikelyClassHistogram h((INT_PTR*)(pInstrumentationData + schema[i + 1].Offset), schema[i + 1].Count); + LikelyClassMethodHistogram h((INT_PTR*)(pInstrumentationData + schema[i + 1].Offset), schema[i + 1].Count); // Use histogram count as number of classes estimate // Report back what we've learned @@ -189,45 +174,45 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* case 1: { - LikelyClassHistogramEntry const hist0 = h.HistogramEntryAt(0); + LikelyClassMethodHistogramEntry const hist0 = h.HistogramEntryAt(0); // Fast path for monomorphic cases - if (ICorJitInfo::IsUnknownHandle(hist0.m_mt)) + if (ICorJitInfo::IsUnknownHandle(hist0.m_handle)) { return 0; } - pLikelyClasses[0].likelihood = 100; - pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)hist0.m_mt; + pLikelyEntries[0].likelihood = 100; + pLikelyEntries[0].handle = hist0.m_handle; return 1; } case 2: { - LikelyClassHistogramEntry const hist0 = h.HistogramEntryAt(0); - LikelyClassHistogramEntry const hist1 = h.HistogramEntryAt(1); // Fast path for two classes - if ((hist0.m_count >= hist1.m_count) && !ICorJitInfo::IsUnknownHandle(hist0.m_mt)) + LikelyClassMethodHistogramEntry const hist0 = h.HistogramEntryAt(0); + LikelyClassMethodHistogramEntry const hist1 = h.HistogramEntryAt(1); + if ((hist0.m_count >= hist1.m_count) && !ICorJitInfo::IsUnknownHandle(hist0.m_handle)) { - pLikelyClasses[0].likelihood = (100 * hist0.m_count) / h.m_totalCount; - pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)hist0.m_mt; + pLikelyEntries[0].likelihood = (100 * hist0.m_count) / h.m_totalCount; + pLikelyEntries[0].handle = hist0.m_handle; - if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist1.m_mt)) + if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist1.m_handle)) { - pLikelyClasses[1].likelihood = (100 * hist1.m_count) / h.m_totalCount; - pLikelyClasses[1].clsHandle = (CORINFO_CLASS_HANDLE)hist1.m_mt; + pLikelyEntries[1].likelihood = (100 * hist1.m_count) / h.m_totalCount; + pLikelyEntries[1].handle = hist1.m_handle; return 2; } return 1; } - if (!ICorJitInfo::IsUnknownHandle(hist1.m_mt)) + if (!ICorJitInfo::IsUnknownHandle(hist1.m_handle)) { - pLikelyClasses[0].likelihood = (100 * hist1.m_count) / h.m_totalCount; - pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)hist1.m_mt; + pLikelyEntries[0].likelihood = (100 * hist1.m_count) / h.m_totalCount; + pLikelyEntries[0].handle = hist1.m_handle; - if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist0.m_mt)) + if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist0.m_handle)) { - pLikelyClasses[1].likelihood = (100 * hist0.m_count) / h.m_totalCount; - pLikelyClasses[1].clsHandle = (CORINFO_CLASS_HANDLE)hist0.m_mt; + pLikelyEntries[1].likelihood = (100 * hist0.m_count) / h.m_totalCount; + pLikelyEntries[1].handle = hist0.m_handle; return 2; } return 1; @@ -237,14 +222,14 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* default: { - LikelyClassHistogramEntry sortedEntries[HISTOGRAM_MAX_SIZE_COUNT]; + LikelyClassMethodHistogramEntry sortedEntries[HISTOGRAM_MAX_SIZE_COUNT]; // Since this method can be invoked without a jit instance we can't use any existing allocators unsigned knownHandles = 0; for (unsigned m = 0; m < h.countHistogramElements; m++) { - LikelyClassHistogramEntry const hist = h.HistogramEntryAt(m); - if (!ICorJitInfo::IsUnknownHandle(hist.m_mt)) + LikelyClassMethodHistogramEntry const hist = h.HistogramEntryAt(m); + if (!ICorJitInfo::IsUnknownHandle(hist.m_handle)) { sortedEntries[knownHandles++] = hist; } @@ -252,7 +237,8 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* // sort by m_count (descending) jitstd::sort(sortedEntries, sortedEntries + knownHandles, - [](const LikelyClassHistogramEntry& h1, const LikelyClassHistogramEntry& h2) -> bool { + [](const LikelyClassMethodHistogramEntry& h1, + const LikelyClassMethodHistogramEntry& h2) -> bool { return h1.m_count > h2.m_count; }); @@ -260,9 +246,9 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* for (size_t hIdx = 0; hIdx < numberOfClasses; hIdx++) { - LikelyClassHistogramEntry const hc = sortedEntries[hIdx]; - pLikelyClasses[hIdx].clsHandle = (CORINFO_CLASS_HANDLE)hc.m_mt; - pLikelyClasses[hIdx].likelihood = hc.m_count * 100 / h.m_totalCount; + LikelyClassMethodHistogramEntry const hc = sortedEntries[hIdx]; + pLikelyEntries[hIdx].handle = hc.m_handle; + pLikelyEntries[hIdx].likelihood = hc.m_count * 100 / h.m_totalCount; } return numberOfClasses; } @@ -276,80 +262,57 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord* } //------------------------------------------------------------------------ -// getRandomClass: find class profile data for an IL offset, and return -// one of the possible classes at random +// getLikelyClasses: find class profile data for an IL offset, and return the most likely classes // // Arguments: +// pLikelyClasses - [OUT] array of likely classes sorted by likelihood (descending). It must be +// at least of 'maxLikelyClasses' (next argument) length. +// The array consists of pairs "clsHandle - likelihood" ordered by likelihood +// (descending) where likelihood can be any value in [0..100] range. clsHandle +// is never null for [0..) range, Items in +// [..maxLikelyClasses) are zeroed if the number +// of classes seen is less than maxLikelyClasses provided. +// maxLikelyClasses - limit for likely classes to output // schema - profile schema // countSchemaItems - number of items in the schema // pInstrumentationData - associated data // ilOffset - il offset of the callvirt -// random - randomness generator // // Returns: -// Randomly observed class, or nullptr. +// Estimated number of classes seen at runtime +// +// Notes: +// A "monomorphic" call site will return likelihood 100 and number of entries = 1. +// +// This is used by the devirtualization logic below, and by crossgen2 when producing +// the R2R image (to reduce the sizecost of carrying the type histogram) +// +// This code can runs without a jit instance present, so JITDUMP and related +// cannot be used. // -CORINFO_CLASS_HANDLE Compiler::getRandomClass(ICorJitInfo::PgoInstrumentationSchema* schema, - UINT32 countSchemaItems, - BYTE* pInstrumentationData, - int32_t ilOffset, - CLRRandom* random) +extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassMethodRecord* pLikelyClasses, + UINT32 maxLikelyClasses, + ICorJitInfo::PgoInstrumentationSchema* schema, + UINT32 countSchemaItems, + BYTE* pInstrumentationData, + int32_t ilOffset) { - if (schema == nullptr) - { - return NO_CLASS_HANDLE; - } - - for (COUNT_T i = 0; i < countSchemaItems; i++) - { - if (schema[i].ILOffset != (int32_t)ilOffset) - { - continue; - } - - if ((schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyClass) && - (schema[i].Count == 1)) - { - INT_PTR result = *(INT_PTR*)(pInstrumentationData + schema[i].Offset); - if (ICorJitInfo::IsUnknownHandle(result)) - { - return NO_CLASS_HANDLE; - } - else - { - return (CORINFO_CLASS_HANDLE)result; - } - } - - bool isHistogramCount = - (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount) || - (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount); - - if (isHistogramCount && (schema[i].Count == 1) && ((i + 1) < countSchemaItems) && - (schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes)) - { - // Form a histogram - // - LikelyClassHistogram h((INT_PTR*)(pInstrumentationData + schema[i + 1].Offset), schema[i + 1].Count); - - if (h.countHistogramElements == 0) - { - return NO_CLASS_HANDLE; - } - - // Choose an entry at random. - // - unsigned randomEntryIndex = random->Next(0, h.countHistogramElements); - LikelyClassHistogramEntry randomEntry = h.HistogramEntryAt(randomEntryIndex); - - if (ICorJitInfo::IsUnknownHandle(randomEntry.m_mt)) - { - return NO_CLASS_HANDLE; - } - - return (CORINFO_CLASS_HANDLE)randomEntry.m_mt; - } - } + return getLikelyClassesOrMethods(pLikelyClasses, maxLikelyClasses, schema, countSchemaItems, pInstrumentationData, + ilOffset, true); +} - return NO_CLASS_HANDLE; +//------------------------------------------------------------------------ +// getLikelyMethods: find method profile data for an IL offset, and return the most likely methods +// +// See documentation on getLikelyClasses above. +// +extern "C" DLLEXPORT UINT32 WINAPI getLikelyMethods(LikelyClassMethodRecord* pLikelyMethods, + UINT32 maxLikelyMethods, + ICorJitInfo::PgoInstrumentationSchema* schema, + UINT32 countSchemaItems, + BYTE* pInstrumentationData, + int32_t ilOffset) +{ + return getLikelyClassesOrMethods(pLikelyMethods, maxLikelyMethods, schema, countSchemaItems, pInstrumentationData, + ilOffset, false); } diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index 915f19525ffc8..05c96837bc4ef 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -1724,6 +1724,25 @@ bool Compiler::optIsLoopClonable(unsigned loopInd) return false; } + // Reject cloning if this is a mid-entry loop and the entry has non-loop predecessors other than its head. + // This loop may be part of a larger looping construct that we didn't recognize. + // + // We should really fix this in optCanonicalizeLoop. + // + if (!loop.lpIsTopEntry()) + { + for (BasicBlock* const entryPred : loop.lpEntry->PredBlocks()) + { + if ((entryPred != loop.lpHead) && !loop.lpContains(entryPred)) + { + JITDUMP("Loop cloning: rejecting loop " FMT_LP + ". Is not top entry, and entry has multiple non-loop preds.\n", + loopInd); + return false; + } + } + } + // We've previously made a decision whether to have separate return epilogs, or branch to one. // There's a GCInfo limitation in the x86 case, so that there can be no more than SET_EPILOGCNT_MAX separate // epilogs. Other architectures have a limit of 4 here for "historical reasons", but this should be revisited diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 98bd11f0fd2d3..0450beb2b2607 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -388,16 +388,6 @@ GenTree* Lowering::LowerNode(GenTree* node) break; #endif -#if !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) - // TODO-ARMARCH-CQ: We should contain this as long as the offset fits. - case GT_OBJ: - if (node->AsObj()->Addr()->OperIsLocalAddr()) - { - node->AsObj()->Addr()->SetContained(); - } - break; -#endif // !TARGET_ARMARCH - case GT_KEEPALIVE: node->gtGetOp1()->SetRegOptional(); break; @@ -1023,7 +1013,6 @@ bool Lowering::TryLowerSwitchToBitTest( GenTree* bitTest = comp->gtNewOperNode(GT_BT, TYP_VOID, bitTableIcon, switchValue); bitTest->gtFlags |= GTF_SET_FLAGS; GenTreeCC* jcc = new (comp, GT_JCC) GenTreeCC(GT_JCC, bbSwitchCondition); - jcc->gtFlags |= GTF_USE_FLAGS; LIR::AsRange(bbSwitch).InsertAfter(switchValue, bitTableIcon, bitTest, jcc); @@ -1031,9 +1020,6 @@ bool Lowering::TryLowerSwitchToBitTest( #endif // TARGET_XARCH } -// NOTE: this method deliberately does not update the call arg table. It must only -// be used by NewPutArg and LowerArg; these functions are responsible for updating -// the call arg table as necessary. void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast) { assert(argSlot != nullptr); @@ -1069,12 +1055,7 @@ void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgO // Notes: // For System V systems with native struct passing (i.e. UNIX_AMD64_ABI defined) // this method allocates a single GT_PUTARG_REG for 1 eightbyte structs and a GT_FIELD_LIST of two GT_PUTARG_REGs -// for two eightbyte structs. -// -// For STK passed structs the method generates GT_PUTARG_STK tree. For System V systems with native struct passing -// (i.e. UNIX_AMD64_ABI defined) this method also sets the GC pointers count and the pointers -// layout object, so the codegen of the GT_PUTARG_STK could use this for optimizing copying to the stack by value. -// (using block copy primitives for non GC pointers and a single TARGET_POINTER_SIZE copy with recording GC info.) +// for two eightbyte structs. For STK passed structs the method generates GT_PUTARG_STK tree. // GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, var_types type) { @@ -1086,19 +1067,6 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, bool isOnStack = (callArg->AbiInfo.GetRegNum() == REG_STK); -#if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) - // Mark contained when we pass struct - // GT_FIELD_LIST is always marked contained when it is generated - if (type == TYP_STRUCT) - { - arg->SetContained(); - if ((arg->OperGet() == GT_OBJ) && (arg->AsObj()->Addr()->OperGet() == GT_LCL_VAR_ADDR)) - { - MakeSrcContained(arg, arg->AsObj()->Addr()); - } - } -#endif - #if FEATURE_ARG_SPLIT // Struct can be split into register(s) and stack on ARM if (compFeatureArgSplit() && callArg->AbiInfo.IsSplit()) @@ -1120,10 +1088,7 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, callArg->AbiInfo.GetStackByteSize(), #endif callArg->AbiInfo.NumRegs, call, putInIncomingArgArea); - // If struct argument is morphed to GT_FIELD_LIST node(s), - // we can know GC info by type of each GT_FIELD_LIST node. - // So we skip setting GC Pointer info. - // + GenTreePutArgSplit* argSplit = putArg->AsPutArgSplit(); for (unsigned regIndex = 0; regIndex < callArg->AbiInfo.NumRegs; regIndex++) { @@ -1132,6 +1097,12 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, if (arg->OperGet() == GT_OBJ) { + arg->SetContained(); + if (arg->AsObj()->Addr()->OperGet() == GT_LCL_VAR_ADDR) + { + MakeSrcContained(arg, arg->AsObj()->Addr()); + } + ClassLayout* layout = arg->AsObj()->GetLayout(); // Set type of registers @@ -1206,8 +1177,6 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, #ifdef DEBUG // Make sure state is correct. The PUTARG_STK has TYP_VOID, as it doesn't produce // a result. So the type of its operand must be the correct type to push on the stack. - // For a FIELD_LIST, this will be the type of the field (not the type of the arg), - // but otherwise it is generally the type of the operand. callArg->CheckIsStruct(); #endif @@ -1245,64 +1214,15 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, #endif call, putInIncomingArgArea); -#ifdef FEATURE_PUT_STRUCT_ARG_STK - // If the ArgTabEntry indicates that this arg is a struct - // get and store the number of slots that are references. - // This is later used in the codegen for PUT_ARG_STK implementation - // for struct to decide whether and how many single eight-byte copies - // to be done (only for reference slots), so gcinfo is emitted. - // For non-reference slots faster/smaller size instructions are used - - // pair copying using XMM registers or rep mov instructions. +#if defined(DEBUG) && defined(FEATURE_PUT_STRUCT_ARG_STK) if (callArg->AbiInfo.IsStruct) { - // We use GT_OBJ only for non-lclVar, non-SIMD, non-FIELD_LIST struct arguments. - if (arg->OperIsLocal()) - { - // This must have a type with a known size (SIMD or has been morphed to a primitive type). - assert(arg->TypeGet() != TYP_STRUCT); - } - else if (arg->OperIs(GT_OBJ)) + // We use GT_OBJ only for non-SIMD struct arguments. + if (arg->OperIs(GT_OBJ)) { assert(!varTypeIsSIMD(arg)); - -#ifdef TARGET_X86 - // On x86 VM lies about the type of a struct containing a pointer sized - // integer field by returning the type of its field as the type of struct. - // Such struct can be passed in a register depending its position in - // parameter list. VM does this unwrapping only one level and therefore - // a type like Struct Foo { Struct Bar { int f}} awlays needs to be - // passed on stack. Also, VM doesn't lie about type of such a struct - // when it is a field of another struct. That is VM doesn't lie about - // the type of Foo.Bar - // - // We now support the promotion of fields that are of type struct. - // However we only support a limited case where the struct field has a - // single field and that single field must be a scalar type. Say Foo.Bar - // field is getting passed as a parameter to a call, Since it is a TYP_STRUCT, - // as per x86 ABI it should always be passed on stack. Therefore GenTree - // node under a PUTARG_STK could be GT_OBJ(GT_LCL_VAR_ADDR(v1)), where - // local v1 could be a promoted field standing for Foo.Bar. Note that - // the type of v1 will be the type of field of Foo.Bar.f when Foo is - // promoted. That is v1 will be a scalar type. In this case we need to - // pass v1 on stack instead of in a register. - // - // TODO-PERF: replace GT_OBJ(GT_LCL_VAR_ADDR(v1)) with v1 if v1 is - // a scalar type and the width of GT_OBJ matches the type size of v1. - // Note that this cannot be done till call node arguments are morphed - // because we should not lose the fact that the type of argument is - // a struct so that the arg gets correctly marked to be passed on stack. - GenTree* objOp1 = arg->gtGetOp1(); - if (objOp1->OperGet() == GT_LCL_VAR_ADDR) - { - unsigned lclNum = objOp1->AsLclVarCommon()->GetLclNum(); - if (comp->lvaTable[lclNum].lvType != TYP_STRUCT) - { - comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::VMNeedsStackAddr)); - } - } -#endif // TARGET_X86 } - else if (!arg->OperIs(GT_FIELD_LIST)) + else if (!arg->TypeIs(TYP_STRUCT)) { #ifdef TARGET_ARM assert((callArg->AbiInfo.GetStackSlotsNumber() == 1) || @@ -1312,7 +1232,7 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, #endif } } -#endif // FEATURE_PUT_STRUCT_ARG_STK +#endif // defined(DEBUG) && defined(FEATURE_PUT_STRUCT_ARG_STK) } } @@ -1459,6 +1379,13 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg, bool late) ReplaceArgWithPutArgOrBitcast(ppArg, putArg); } } + + arg = *ppArg; + + if (arg->OperIs(GT_PUTARG_STK)) + { + LowerPutArgStk(arg->AsPutArgStk()); + } } #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) @@ -2283,10 +2210,58 @@ void Lowering::LowerCFGCall(GenTreeCall* call) } GenTree* callTarget = call->gtCallType == CT_INDIRECT ? call->gtCallAddr : call->gtControlExpr; - if ((callTarget == nullptr) || callTarget->IsIntegralConst()) + if (callTarget == nullptr) { - // This is a direct call, no CFG check is necessary. - return; + assert((call->gtCallType != CT_INDIRECT) && (!call->IsVirtual() || call->IsVirtualStubRelativeIndir())); + if (!call->IsVirtual()) + { + // Direct call with stashed address + return; + } + + // This is a VSD call with the call target being null because we are + // supposed to load it from the indir cell. Due to CFG we will need + // this address twice, and at least on ARM64 we do not want to + // materialize the constant both times. + CallArg* indirCellArg = call->gtArgs.FindWellKnownArg(WellKnownArg::VirtualStubCell); + assert((indirCellArg != nullptr) && indirCellArg->GetNode()->OperIs(GT_PUTARG_REG)); + + GenTreeOp* putArgNode = indirCellArg->GetNode()->AsOp(); + LIR::Use indirCellArgUse(BlockRange(), &putArgNode->gtOp1, putArgNode); + + // On non-xarch, we create a local even for constants. On xarch cloning + // the constant is better since it can be contained in the load below. + bool cloneConsts = false; +#ifdef TARGET_XARCH + cloneConsts = true; +#endif + + GenTree* indirCellClone; + + if (indirCellArgUse.Def()->OperIs(GT_LCL_VAR) || (cloneConsts && indirCellArgUse.Def()->IsCnsIntOrI())) + { + indirCellClone = comp->gtClone(indirCellArgUse.Def()); + } + else + { + unsigned newLcl = indirCellArgUse.ReplaceWithLclVar(comp); + indirCellClone = comp->gtNewLclvNode(newLcl, TYP_I_IMPL); + } + + callTarget = Ind(indirCellClone); + LIR::Range controlExprRange = LIR::SeqTree(comp, callTarget); + ContainCheckRange(controlExprRange); + + BlockRange().InsertBefore(call, std::move(controlExprRange)); + call->gtControlExpr = callTarget; + } + else + { + if (callTarget->IsIntegralConst()) + { + // This is a direct call, no CFG check is necessary. + return; + } } CFGCallKind cfgKind = call->GetCFGCallKind(); @@ -2727,7 +2702,6 @@ GenTree* Lowering::DecomposeLongCompare(GenTree* cmp) GenTree* jcc = cmpUse.User(); jcc->AsOp()->gtOp1 = nullptr; jcc->ChangeOper(GT_JCC); - jcc->gtFlags |= GTF_USE_FLAGS; jcc->AsCC()->gtCondition = GenCondition::FromIntegralRelop(condition, cmp->IsUnsigned()); } else @@ -2735,7 +2709,6 @@ GenTree* Lowering::DecomposeLongCompare(GenTree* cmp) cmp->AsOp()->gtOp1 = nullptr; cmp->AsOp()->gtOp2 = nullptr; cmp->ChangeOper(GT_SETCC); - cmp->gtFlags |= GTF_USE_FLAGS; cmp->AsCC()->gtCondition = GenCondition::FromIntegralRelop(condition, cmp->IsUnsigned()); } @@ -2983,8 +2956,6 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) cmpUse.ReplaceWith(cc); } - cc->gtFlags |= GTF_USE_FLAGS; - return cmp->gtNext; } #endif // TARGET_XARCH @@ -3052,7 +3023,6 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) GenCondition condition = GenCondition::FromIntegralRelop(cmp); cc->ChangeOper(ccOp); cc->AsCC()->gtCondition = condition; - cc->gtFlags |= GTF_USE_FLAGS; return next; } @@ -3270,7 +3240,6 @@ GenTreeCC* Lowering::LowerNodeCC(GenTree* node, GenCondition condition) if (cc != nullptr) { node->gtFlags |= GTF_SET_FLAGS; - cc->gtFlags |= GTF_USE_FLAGS; } // Remove the chain of EQ/NE(x, 0) relop nodes, if any. Note that if a SETCC was @@ -3539,13 +3508,13 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) // Do it now. GenTreeIndir* indir = src->AsIndir(); LowerIndir(indir); + } #if defined(TARGET_XARCH) - if (varTypeIsSmall(lclRegType)) - { - indir->SetDontExtend(); - } -#endif // TARGET_XARCH + if (varTypeIsSmall(lclRegType)) + { + src->SetDontExtend(); } +#endif // TARGET_XARCH } convertToStoreObj = false; #else // TARGET_ARM64 @@ -3814,18 +3783,18 @@ void Lowering::LowerCallStruct(GenTreeCall* call) if (GlobalJitOptions::compFeatureHfa) { - if (comp->IsHfa(call)) + if (comp->IsHfa(call->gtRetClsHnd)) { #if defined(TARGET_ARM64) - assert(comp->GetHfaCount(call) == 1); + assert(comp->GetHfaCount(call->gtRetClsHnd) == 1); #elif defined(TARGET_ARM) // ARM returns double in 2 float registers, but // `call->HasMultiRegRetVal()` count double registers. - assert(comp->GetHfaCount(call) <= 2); + assert(comp->GetHfaCount(call->gtRetClsHnd) <= 2); #else // !TARGET_ARM64 && !TARGET_ARM NYI("Unknown architecture"); #endif // !TARGET_ARM64 && !TARGET_ARM - var_types hfaType = comp->GetHfaType(call); + var_types hfaType = comp->GetHfaType(call->gtRetClsHnd); if (call->TypeIs(hfaType)) { return; @@ -5127,7 +5096,7 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call) // Skip inserting the indirection node to load the address that is already // computed in the VSD stub arg register as a hidden parameter. Instead during the // codegen, just load the call target from there. - shouldOptimizeVirtualStubCall = !comp->opts.IsCFGEnabled(); + shouldOptimizeVirtualStubCall = true; #endif if (!shouldOptimizeVirtualStubCall) @@ -5395,7 +5364,7 @@ bool Lowering::TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* par // Check if we can "contain" LEA(BFIZ) in order to extend 32bit index to 64bit as part of load/store. if ((index != nullptr) && index->OperIs(GT_BFIZ) && index->gtGetOp1()->OperIs(GT_CAST) && - index->gtGetOp2()->IsCnsIntOrI() && (varTypeIsIntegral(targetType) || varTypeIsFloating(targetType))) + index->gtGetOp2()->IsCnsIntOrI() && !varTypeIsStruct(targetType)) { // BFIZ node is a binary op where op1 is GT_CAST and op2 is GT_CNS_INT GenTreeCast* cast = index->gtGetOp1()->AsCast(); @@ -5838,7 +5807,8 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) #if defined(TARGET_ARM64) if (divMod->OperIs(GT_MOD) && divisor->IsIntegralConstPow2()) { - return LowerModPow2(node); + LowerModPow2(node); + return node->gtNext; } assert(node->OperGet() != GT_MOD); #endif // TARGET_ARM64 @@ -7374,9 +7344,9 @@ bool Lowering::TryTransformStoreObjAsStoreInd(GenTreeBlk* blkNode) } #if defined(TARGET_XARCH) - if (varTypeIsSmall(regType) && src->OperIs(GT_IND)) + if (varTypeIsSmall(regType) && src->OperIs(GT_IND, GT_LCL_FLD)) { - src->AsIndir()->SetDontExtend(); + src->SetDontExtend(); } #endif // TARGET_XARCH @@ -7414,6 +7384,7 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) if (arg->IsCnsFltOrDbl()) { + noway_assert(constArgCount < ArrLen(constArgValues)); constArgValues[constArgCount] = static_cast(arg->AsDblCon()->gtDconVal); constArgCount++; } @@ -7426,10 +7397,14 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) BlockRange().Remove(arg); } - assert(sizeof(constArgValues) == 16); + // For SIMD12, even though there might be 12 bytes of constants, we need to store 16 bytes of data + // since we've bashed the node the TYP_SIMD16 and do a 16-byte indirection. + assert(varTypeIsSIMD(simdNode)); + const unsigned cnsSize = genTypeSize(simdNode); + assert(cnsSize <= sizeof(constArgValues)); - unsigned cnsSize = sizeof(constArgValues); - unsigned cnsAlign = (comp->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : 1; + const unsigned cnsAlign = + (comp->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : emitter::dataSection::MIN_DATA_ALIGN; CORINFO_FIELD_HANDLE hnd = comp->GetEmitter()->emitBlkConst(constArgValues, cnsSize, cnsAlign, simdNode->GetSimdBaseType()); diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index 7e6acf6f03009..08eeb58143336 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -351,11 +351,12 @@ class Lowering final : public Phase GenTree* TryLowerAndOpToResetLowestSetBit(GenTreeOp* andNode); GenTree* TryLowerAndOpToExtractLowestSetBit(GenTreeOp* andNode); GenTree* TryLowerAndOpToAndNot(GenTreeOp* andNode); + GenTree* TryLowerXorOpToGetMaskUpToLowestSetBit(GenTreeOp* xorNode); void LowerBswapOp(GenTreeOp* node); #elif defined(TARGET_ARM64) bool IsValidConstForMovImm(GenTreeHWIntrinsic* node); void LowerHWIntrinsicFusedMultiplyAddScalar(GenTreeHWIntrinsic* node); - GenTree* LowerModPow2(GenTree* node); + void LowerModPow2(GenTree* node); GenTree* LowerAddForPossibleContainment(GenTreeOp* node); #endif // !TARGET_XARCH && !TARGET_ARM64 #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 5ee0c27767ee1..ed77d2a954f17 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -104,6 +104,7 @@ bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) const case GT_LE: case GT_GE: case GT_GT: + case GT_CMP: case GT_BOUNDS_CHECK: return emitter::emitIns_valid_imm_for_cmp(immVal, size); case GT_AND: @@ -574,6 +575,44 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT addr->SetContained(); } +//------------------------------------------------------------------------ +// LowerPutArgStk: Lower a GT_PUTARG_STK. +// +// Arguments: +// putArgStk - The node to lower +// +void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) +{ + GenTree* src = putArgStk->Data(); + + if (src->TypeIs(TYP_STRUCT)) + { + // STRUCT args (FIELD_LIST / OBJ / LCL_VAR / LCL_FLD) will always be contained. + MakeSrcContained(putArgStk, src); + + // TODO-ADDR: always perform this transformation in local morph and delete this code. + if (src->OperIs(GT_OBJ) && src->AsObj()->Addr()->OperIsLocalAddr()) + { + GenTreeLclVarCommon* lclAddrNode = src->AsObj()->Addr()->AsLclVarCommon(); + unsigned lclNum = lclAddrNode->GetLclNum(); + unsigned lclOffs = lclAddrNode->GetLclOffs(); + ClassLayout* layout = src->AsObj()->GetLayout(); + + src->ChangeOper(GT_LCL_FLD); + src->AsLclFld()->SetLclNum(lclNum); + src->AsLclFld()->SetLclOffs(lclOffs); + src->AsLclFld()->SetLayout(layout); + + BlockRange().Remove(lclAddrNode); + } + else if (src->OperIs(GT_LCL_VAR)) + { + // TODO-1stClassStructs: support struct enregistration here by retyping "src" to its register type. + comp->lvaSetVarDoNotEnregister(src->AsLclVar()->GetLclNum() DEBUGARG(DoNotEnregisterReason::IsStructArg)); + } + } +} + //------------------------------------------------------------------------ // LowerCast: Lower GT_CAST(srcType, DstType) nodes. // @@ -661,41 +700,26 @@ void Lowering::LowerRotate(GenTree* tree) // Arguments: // tree - the node to lower // -// Return Value: -// A new tree node if it changed. -// // Notes: -// {expr} % {cns} -// Logically turns into: -// let a = {expr} -// if a > 0 then (a & ({cns} - 1)) else -(-a & ({cns} - 1)) -// which then turns into: -// and reg1, reg0, #({cns} - 1) -// negs reg0, reg0 -// and reg0, reg0, #({cns} - 1) -// csneg reg0, reg1, reg0, mi // TODO: We could do this optimization in morph but we do not have // a conditional select op in HIR. At some point, we may // introduce such an op. -GenTree* Lowering::LowerModPow2(GenTree* node) +void Lowering::LowerModPow2(GenTree* node) { assert(node->OperIs(GT_MOD)); - GenTree* mod = node; - GenTree* dividend = mod->gtGetOp1(); - GenTree* divisor = mod->gtGetOp2(); + GenTreeOp* mod = node->AsOp(); + GenTree* dividend = mod->gtGetOp1(); + GenTree* divisor = mod->gtGetOp2(); + + JITDUMP("Lower: optimize X MOD POW2"); assert(divisor->IsIntegralConstPow2()); const var_types type = mod->TypeGet(); assert((type == TYP_INT) || (type == TYP_LONG)); - LIR::Use use; - if (!BlockRange().TryGetUse(node, &use)) - { - return nullptr; - } - - ssize_t cnsValue = static_cast(divisor->AsIntConCommon()->IntegralValue()) - 1; + ssize_t divisorCnsValue = static_cast(divisor->AsIntConCommon()->IntegralValue()); + ssize_t divisorCnsValueMinusOne = divisorCnsValue - 1; BlockRange().Remove(divisor); @@ -707,39 +731,64 @@ GenTree* Lowering::LowerModPow2(GenTree* node) GenTree* dividend2 = comp->gtClone(dividend); BlockRange().InsertAfter(dividend, dividend2); - GenTreeIntCon* cns = comp->gtNewIconNode(cnsValue, type); + GenTreeIntCon* cns = comp->gtNewIconNode(divisorCnsValueMinusOne, type); BlockRange().InsertAfter(dividend2, cns); GenTree* const trueExpr = comp->gtNewOperNode(GT_AND, type, dividend, cns); BlockRange().InsertAfter(cns, trueExpr); LowerNode(trueExpr); - GenTree* const neg = comp->gtNewOperNode(GT_NEG, type, dividend2); - neg->gtFlags |= GTF_SET_FLAGS; - BlockRange().InsertAfter(trueExpr, neg); - - GenTreeIntCon* cns2 = comp->gtNewIconNode(cnsValue, type); - BlockRange().InsertAfter(neg, cns2); - - GenTree* const falseExpr = comp->gtNewOperNode(GT_AND, type, neg, cns2); - BlockRange().InsertAfter(cns2, falseExpr); - LowerNode(falseExpr); - - GenTree* const cc = comp->gtNewOperNode(GT_CSNEG_MI, type, trueExpr, falseExpr); - cc->gtFlags |= GTF_USE_FLAGS; - - JITDUMP("Lower: optimize X MOD POW2"); - DISPNODE(mod); - JITDUMP("to:\n"); - DISPNODE(cc); - - BlockRange().InsertBefore(mod, cc); - ContainCheckNode(cc); - BlockRange().Remove(mod); + if (divisorCnsValue == 2) + { + // {expr} % 2 + // Logically turns into: + // let a = {expr} + // if a < 0 then -(a & 1) else (a & 1) + // which then turns into: + // and reg1, reg0, #1 + // cmp reg0, #0 + // cneg reg0, reg1, lt + + GenTreeIntCon* cnsZero = comp->gtNewIconNode(0, type); + BlockRange().InsertAfter(trueExpr, cnsZero); + + GenTree* const cmp = comp->gtNewOperNode(GT_CMP, type, dividend2, cnsZero); + cmp->gtFlags |= GTF_SET_FLAGS; + BlockRange().InsertAfter(cnsZero, cmp); + LowerNode(cmp); - use.ReplaceWith(cc); + mod->ChangeOper(GT_CNEG_LT); + mod->gtOp1 = trueExpr; + } + else + { + // {expr} % {cns} + // Logically turns into: + // let a = {expr} + // if a > 0 then (a & ({cns} - 1)) else -(-a & ({cns} - 1)) + // which then turns into: + // and reg1, reg0, #({cns} - 1) + // negs reg0, reg0 + // and reg0, reg0, #({cns} - 1) + // csneg reg0, reg1, reg0, mi + + GenTree* const neg = comp->gtNewOperNode(GT_NEG, type, dividend2); + neg->gtFlags |= GTF_SET_FLAGS; + BlockRange().InsertAfter(trueExpr, neg); + + GenTreeIntCon* cns2 = comp->gtNewIconNode(divisorCnsValueMinusOne, type); + BlockRange().InsertAfter(neg, cns2); + + GenTree* const falseExpr = comp->gtNewOperNode(GT_AND, type, neg, cns2); + BlockRange().InsertAfter(cns2, falseExpr); + LowerNode(falseExpr); + + mod->ChangeOper(GT_CSNEG_MI); + mod->gtOp1 = trueExpr; + mod->gtOp2 = falseExpr; + } - return cc->gtNext; + ContainCheckNode(mod); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lowerloongarch64.cpp b/src/coreclr/jit/lowerloongarch64.cpp index 7a2cde0c4f5fb..1de03b57e8e92 100644 --- a/src/coreclr/jit/lowerloongarch64.cpp +++ b/src/coreclr/jit/lowerloongarch64.cpp @@ -416,6 +416,30 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT addr->SetContained(); } +//------------------------------------------------------------------------ +// LowerPutArgStk: Lower a GT_PUTARG_STK. +// +// Arguments: +// putArgStk - The node to lower +// +void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) +{ + GenTree* src = putArgStk->Data(); + + if (src->TypeIs(TYP_STRUCT)) + { + // STRUCT args (FIELD_LIST / OBJ) will always be contained. + MakeSrcContained(putArgStk, src); + + // Additionally, codegen supports containment of local addresses under OBJs. + if (src->OperIs(GT_OBJ) && src->AsObj()->Addr()->OperIs(GT_LCL_VAR_ADDR)) + { + // TODO-LOONGARCH64-CQ: support containment of LCL_FLD_ADDR too. + MakeSrcContained(src, src->AsObj()->Addr()); + } + } +} + //------------------------------------------------------------------------ // LowerCast: Lower GT_CAST(srcType, DstType) nodes. // diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 46990d9f6dbc6..e8be8b615c6d8 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -174,24 +174,35 @@ GenTree* Lowering::LowerMul(GenTreeOp* mul) GenTree* Lowering::LowerBinaryArithmetic(GenTreeOp* binOp) { #ifdef FEATURE_HW_INTRINSICS - if (comp->opts.OptimizationEnabled() && binOp->OperIs(GT_AND) && varTypeIsIntegral(binOp)) + if (comp->opts.OptimizationEnabled() && varTypeIsIntegral(binOp)) { - GenTree* replacementNode = TryLowerAndOpToAndNot(binOp); - if (replacementNode != nullptr) + if (binOp->OperIs(GT_AND)) { - return replacementNode->gtNext; - } + GenTree* replacementNode = TryLowerAndOpToAndNot(binOp); + if (replacementNode != nullptr) + { + return replacementNode->gtNext; + } - replacementNode = TryLowerAndOpToResetLowestSetBit(binOp); - if (replacementNode != nullptr) - { - return replacementNode->gtNext; - } + replacementNode = TryLowerAndOpToResetLowestSetBit(binOp); + if (replacementNode != nullptr) + { + return replacementNode->gtNext; + } - replacementNode = TryLowerAndOpToExtractLowestSetBit(binOp); - if (replacementNode != nullptr) + replacementNode = TryLowerAndOpToExtractLowestSetBit(binOp); + if (replacementNode != nullptr) + { + return replacementNode->gtNext; + } + } + else if (binOp->OperIs(GT_XOR)) { - return replacementNode->gtNext; + GenTree* replacementNode = TryLowerXorOpToGetMaskUpToLowestSetBit(binOp); + if (replacementNode != nullptr) + { + return replacementNode->gtNext; + } } } #endif @@ -455,14 +466,11 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT // LowerPutArgStk: Lower a GT_PUTARG_STK. // // Arguments: -// tree - The node of interest -// -// Return Value: -// None. +// putArgStk - The node of interest // void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) { - GenTree* src = putArgStk->gtGetOp1(); + GenTree* src = putArgStk->Data(); bool srcIsLocal = src->OperIsLocalRead(); if (src->OperIs(GT_FIELD_LIST)) @@ -533,9 +541,11 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) #ifdef FEATURE_PUT_STRUCT_ARG_STK if (src->TypeIs(TYP_STRUCT)) { - ClassLayout* layout = src->AsObj()->GetLayout(); + assert(src->OperIs(GT_OBJ) || src->OperIsLocalRead()); + + ClassLayout* layout = src->GetLayout(comp); var_types regType = layout->GetRegisterType(); - srcIsLocal |= src->AsObj()->Addr()->OperIsLocalAddr(); + srcIsLocal |= src->OperIs(GT_OBJ) && src->AsObj()->Addr()->OperIsLocalAddr(); if (regType == TYP_UNDEF) { @@ -545,30 +555,24 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) // The cpyXXXX code is rather complex and this could cause it to be more complex, but // it might be the right thing to do. - unsigned size = putArgStk->GetStackByteSize(); - unsigned loadSize = layout->GetSize(); - - assert(loadSize <= size); + // If possible, widen the load, this results in more compact code. + unsigned loadSize = srcIsLocal ? roundUp(layout->GetSize(), TARGET_POINTER_SIZE) : layout->GetSize(); + putArgStk->SetArgLoadSize(loadSize); // TODO-X86-CQ: The helper call either is not supported on x86 or required more work // (I don't know which). - if (!layout->HasGCPtr()) { #ifdef TARGET_X86 // Codegen for "Kind::Push" will always load bytes in TARGET_POINTER_SIZE - // chunks. As such, the correctness of this code depends on the fact that - // morph will copy any "mis-sized" (too small) non-local OBJs into a temp, - // thus preventing any possible out-of-bounds memory reads. - assert(((layout->GetSize() % TARGET_POINTER_SIZE) == 0) || src->OperIsLocalRead() || - (src->OperIsIndir() && src->AsIndir()->Addr()->IsLocalAddrExpr())); - if (size < XMM_REGSIZE_BYTES) + // chunks. As such, we'll only use this path for correctly-sized sources. + if ((loadSize < XMM_REGSIZE_BYTES) && ((loadSize % TARGET_POINTER_SIZE) == 0)) { putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Push; } else #endif // TARGET_X86 - if (size <= CPBLK_UNROLL_LIMIT) + if (loadSize <= CPBLK_UNROLL_LIMIT) { putArgStk->gtPutArgStkKind = GenTreePutArgStk::Kind::Unroll; } @@ -589,14 +593,25 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) #endif // !TARGET_X86 } - // Always mark the OBJ and ADDR as contained trees by the putarg_stk. The codegen will deal with this tree. - MakeSrcContained(putArgStk, src); if (src->OperIs(GT_OBJ) && src->AsObj()->Addr()->OperIsLocalAddr()) { - // If the source address is the address of a lclVar, make the source address contained to avoid - // unnecessary copies. - MakeSrcContained(putArgStk, src->AsObj()->Addr()); + // TODO-ADDR: always perform this transformation in local morph and delete this code. + GenTreeLclVarCommon* lclAddrNode = src->AsObj()->Addr()->AsLclVarCommon(); + BlockRange().Remove(lclAddrNode); + + src->ChangeOper(GT_LCL_FLD); + src->AsLclFld()->SetLclNum(lclAddrNode->GetLclNum()); + src->AsLclFld()->SetLclOffs(lclAddrNode->GetLclOffs()); + src->AsLclFld()->SetLayout(layout); } + else if (src->OperIs(GT_LCL_VAR)) + { + comp->lvaSetVarDoNotEnregister(src->AsLclVar()->GetLclNum() + DEBUGARG(DoNotEnregisterReason::IsStructArg)); + } + + // Always mark the OBJ/LCL_VAR/LCL_FLD as contained trees. + MakeSrcContained(putArgStk, src); } else { @@ -604,13 +619,17 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) // so if possible, widen the load to avoid the sign/zero-extension. if (varTypeIsSmall(regType) && srcIsLocal) { - assert(putArgStk->GetStackByteSize() <= genTypeSize(TYP_INT)); + assert(genTypeSize(TYP_INT) <= putArgStk->GetStackByteSize()); regType = TYP_INT; } - src->SetOper(GT_IND); src->ChangeType(regType); - LowerIndir(src->AsIndir()); + + if (src->OperIs(GT_OBJ)) + { + src->SetOper(GT_IND); + LowerIndir(src->AsIndir()); + } } } @@ -4056,6 +4075,93 @@ GenTree* Lowering::TryLowerAndOpToAndNot(GenTreeOp* andNode) return andnNode; } +//---------------------------------------------------------------------------------------------- +// Lowering::TryLowerXorOpToGetMaskUpToLowestSetBit: Lowers a tree XOR(X, ADD(X, -1)) to +// HWIntrinsic::GetMaskUpToLowestSetBit +// +// Arguments: +// xorNode - GT_XOR node of integral type +// +// Return Value: +// Returns the replacement node if one is created else nullptr indicating no replacement +// +// Notes: +// Performs containment checks on the replacement node if one is created +GenTree* Lowering::TryLowerXorOpToGetMaskUpToLowestSetBit(GenTreeOp* xorNode) +{ + assert(xorNode->OperIs(GT_XOR) && varTypeIsIntegral(xorNode)); + + GenTree* op1 = xorNode->gtGetOp1(); + if (!op1->OperIs(GT_LCL_VAR) || comp->lvaGetDesc(op1->AsLclVar())->IsAddressExposed()) + { + return nullptr; + } + + GenTree* op2 = xorNode->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; + } + + // Subsequent nodes may rely on CPU flags set by these nodes in which case we cannot remove them + if (((addOp2->gtFlags & GTF_SET_FLAGS) != 0) || ((op2->gtFlags & GTF_SET_FLAGS) != 0) || + ((xorNode->gtFlags & GTF_SET_FLAGS) != 0)) + { + return nullptr; + } + + NamedIntrinsic intrinsic; + if (xorNode->TypeIs(TYP_LONG) && comp->compOpportunisticallyDependsOn(InstructionSet_BMI1_X64)) + { + intrinsic = NamedIntrinsic::NI_BMI1_X64_GetMaskUpToLowestSetBit; + } + else if (comp->compOpportunisticallyDependsOn(InstructionSet_BMI1)) + { + intrinsic = NamedIntrinsic::NI_BMI1_GetMaskUpToLowestSetBit; + } + else + { + return nullptr; + } + + LIR::Use use; + if (!BlockRange().TryGetUse(xorNode, &use)) + { + return nullptr; + } + + GenTreeHWIntrinsic* blsmskNode = comp->gtNewScalarHWIntrinsicNode(xorNode->TypeGet(), op1, intrinsic); + + JITDUMP("Lower: optimize XOR(X, ADD(X, -1)))\n"); + DISPNODE(xorNode); + JITDUMP("to:\n"); + DISPNODE(blsmskNode); + + use.ReplaceWith(blsmskNode); + + BlockRange().InsertBefore(xorNode, blsmskNode); + BlockRange().Remove(xorNode); + BlockRange().Remove(op2); + BlockRange().Remove(addOp1); + BlockRange().Remove(addOp2); + + ContainCheckHWIntrinsic(blsmskNode); + + return blsmskNode; +} + //---------------------------------------------------------------------------------------------- // Lowering::LowerBswapOp: Tries to contain GT_BSWAP node when possible // @@ -4613,22 +4719,6 @@ void Lowering::ContainCheckCallOperands(GenTreeCall* call) MakeSrcContained(call, ctrlExpr); } } - - for (CallArg& arg : call->gtArgs.EarlyArgs()) - { - if (arg.GetEarlyNode()->OperIs(GT_PUTARG_STK)) - { - LowerPutArgStk(arg.GetEarlyNode()->AsPutArgStk()); - } - } - - for (CallArg& arg : call->gtArgs.LateArgs()) - { - if (arg.GetLateNode()->OperIs(GT_PUTARG_STK)) - { - LowerPutArgStk(arg.GetLateNode()->AsPutArgStk()); - } - } } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lsraarmarch.cpp b/src/coreclr/jit/lsraarmarch.cpp index 4a9eefef350c5..3d1cf8540a142 100644 --- a/src/coreclr/jit/lsraarmarch.cpp +++ b/src/coreclr/jit/lsraarmarch.cpp @@ -403,20 +403,19 @@ int LinearScan::BuildPutArgStk(GenTreePutArgStk* argNode) { assert(argNode->gtOper == GT_PUTARG_STK); - GenTree* putArgChild = argNode->gtGetOp1(); - - int srcCount = 0; + GenTree* src = argNode->Data(); + int srcCount = 0; - // Do we have a TYP_STRUCT argument (or a GT_FIELD_LIST), if so it must be a multireg pass-by-value struct - if (putArgChild->TypeIs(TYP_STRUCT) || putArgChild->OperIs(GT_FIELD_LIST)) + // Do we have a TYP_STRUCT argument, if so it must be a multireg pass-by-value struct + if (src->TypeIs(TYP_STRUCT)) { // We will use store instructions that each write a register sized value - if (putArgChild->OperIs(GT_FIELD_LIST)) + if (src->OperIs(GT_FIELD_LIST)) { - assert(putArgChild->isContained()); + assert(src->isContained()); // We consume all of the items in the GT_FIELD_LIST - for (GenTreeFieldList::Use& use : putArgChild->AsFieldList()->Uses()) + for (GenTreeFieldList::Use& use : src->AsFieldList()->Uses()) { BuildUse(use.GetNode()); srcCount++; @@ -443,36 +442,25 @@ int LinearScan::BuildPutArgStk(GenTreePutArgStk* argNode) buildInternalIntRegisterDefForNode(argNode); #endif // TARGET_ARM64 - if (putArgChild->OperGet() == GT_OBJ) + assert(src->isContained()); + + if (src->OperIs(GT_OBJ)) { - assert(putArgChild->isContained()); - GenTree* objChild = putArgChild->gtGetOp1(); - if (objChild->OperGet() == GT_LCL_VAR_ADDR) - { - // We will generate all of the code for the GT_PUTARG_STK, the GT_OBJ and the GT_LCL_VAR_ADDR - // as one contained operation, and there are no source registers. - // - assert(objChild->isContained()); - } - else - { - // We will generate all of the code for the GT_PUTARG_STK and its child node - // as one contained operation - // - srcCount = BuildOperandUses(objChild); - } + // Build uses for the address to load from. + // + srcCount = BuildOperandUses(src->AsObj()->Addr()); } else { // No source registers. - putArgChild->OperIs(GT_LCL_VAR); + assert(src->OperIs(GT_LCL_VAR, GT_LCL_FLD)); } } } else { - assert(!putArgChild->isContained()); - srcCount = BuildOperandUses(putArgChild); + assert(!src->isContained()); + srcCount = BuildOperandUses(src); #if defined(FEATURE_SIMD) if (compMacOsArm64Abi() && argNode->GetStackByteSize() == 12) { @@ -820,13 +808,6 @@ int LinearScan::BuildCast(GenTreeCast* cast) buildInternalFloatRegisterDefForNode(cast, RBM_ALLFLOAT); setInternalRegsDelayFree = true; } -#else - // Overflow checking cast from TYP_LONG to TYP_INT requires a temporary register to - // store the min and max immediate values that cannot be encoded in the CMP instruction. - if (cast->gtOverflow() && varTypeIsLong(srcType) && !cast->IsUnsigned() && (castType == TYP_INT)) - { - buildInternalIntRegisterDefForNode(cast); - } #endif int srcCount = BuildOperandUses(src); diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 5386ed5769558..6ed5665febdc5 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -1561,21 +1561,31 @@ int LinearScan::BuildPutArgStk(GenTreePutArgStk* putArgStk) return BuildOperandUses(src); } - ssize_t size = putArgStk->GetStackByteSize(); + unsigned loadSize = putArgStk->GetArgLoadSize(); switch (putArgStk->gtPutArgStkKind) { case GenTreePutArgStk::Kind::Unroll: // If we have a remainder smaller than XMM_REGSIZE_BYTES, we need an integer temp reg. - if ((size % XMM_REGSIZE_BYTES) != 0) + if ((loadSize % XMM_REGSIZE_BYTES) != 0) { regMaskTP regMask = allRegs(TYP_INT); +#ifdef TARGET_X86 + // Storing at byte granularity requires a byteable register. + if ((loadSize & 1) != 0) + { + regMask &= allByteRegs(); + } +#endif // TARGET_X86 buildInternalIntRegisterDefForNode(putArgStk, regMask); } - if (size >= XMM_REGSIZE_BYTES) +#ifdef TARGET_X86 + if (loadSize >= 8) +#else + if (loadSize >= XMM_REGSIZE_BYTES) +#endif { - // If we have a buffer larger than or equal to XMM_REGSIZE_BYTES, reserve - // an XMM register to use it for a series of 16-byte loads and stores. + // See "genStructPutArgUnroll" -- we will use this XMM register for wide stores. buildInternalFloatRegisterDefForNode(putArgStk, internalFloatRegCandidates()); SetContainsAVXFlags(); } @@ -2481,9 +2491,9 @@ int LinearScan::BuildCast(GenTreeCast* cast) assert(!varTypeIsLong(srcType) || (src->OperIs(GT_LONG) && src->isContained())); #else - // Overflow checking cast from TYP_(U)LONG to TYP_UINT requires a temporary + // Overflow checking cast from TYP_(U)LONG to TYP_(U)INT requires a temporary // register to extract the upper 32 bits of the 64 bit source register. - if (cast->gtOverflow() && varTypeIsLong(srcType) && (castType == TYP_UINT)) + if (cast->gtOverflow() && varTypeIsLong(srcType) && varTypeIsInt(castType)) { // Here we don't need internal register to be different from targetReg, // rather require it to be different from operand's reg. diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index ec5d602d5eb64..22fe9739444b4 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -179,16 +179,7 @@ GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, bool morphAr // GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) { - GenTree* oper = tree->CastOp(); - - if (fgGlobalMorph && (oper->gtOper == GT_ADDR)) - { - // Make sure we've checked if 'oper' is an address of an implicit-byref parameter. - // If it is, fgMorphImplicitByRefArgs will change its type, and we want the cast - // morphing code to see that type. - fgMorphImplicitByRefArgs(oper); - } - + GenTree* oper = tree->CastOp(); var_types srcType = genActualType(oper); var_types dstType = tree->CastToType(); unsigned dstSize = genTypeSize(dstType); @@ -744,6 +735,12 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) unsigned argCount = CountArgs(); + // Previous argument with GTF_EXCEPT + GenTree* prevExceptionTree = nullptr; + // Exceptions previous tree with GTF_EXCEPT may throw (computed lazily, may + // be empty) + ExceptionSetFlags prevExceptionFlags = ExceptionSetFlags::None; + for (CallArg& arg : Args()) { GenTree* argx = arg.GetEarlyNode(); @@ -755,15 +752,14 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) continue; } + bool canEvalToTemp = true; if (arg.AbiInfo.GetRegNum() == REG_STK) { assert(m_hasStackArgs); #if !FEATURE_FIXED_OUT_ARGS - // On x86 we use push instructions to pass arguments: - // The non-register arguments are evaluated and pushed in order - // and they are never evaluated into temps - // - continue; + // Non-register arguments are evaluated and pushed in order; they + // should never go in the late arg list. + canEvalToTemp = false; #endif } #if FEATURE_ARG_SPLIT @@ -796,17 +792,20 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) if (argx->gtFlags & GTF_ASG) { - // If this is not the only argument, or it's a copyblk, or it already evaluates the expression to - // a tmp, then we need a temp in the late arg list. - if ((argCount > 1) || argx->OperIsCopyBlkOp() -#ifdef FEATURE_FIXED_OUT_ARGS - || arg.m_isTmp // Protect this by "FEATURE_FIXED_OUT_ARGS" to preserve the property - // that we only have late non-register args when that feature is on. -#endif - ) + // If this is not the only argument, or it's a copyblk, or it + // already evaluates the expression to a tmp then we need a temp in + // the late arg list. + // In the latter case this might not even be a value; + // fgMakeOutgoingStructArgCopy will leave the copying nodes here + // for FEATURE_FIXED_OUT_ARGS. + if (canEvalToTemp && ((argCount > 1) || argx->OperIsCopyBlkOp() || (FEATURE_FIXED_OUT_ARGS && arg.m_isTmp))) { SetNeedsTemp(&arg); } + else + { + assert(argx->IsValue()); + } // For all previous arguments, unless they are a simple constant // we require that they be evaluated into temps @@ -817,6 +816,16 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) break; } +#if !FEATURE_FIXED_OUT_ARGS + if (prevArg.AbiInfo.GetRegNum() == REG_STK) + { + // All stack args are already evaluated and placed in order + // in this case; we only need to check this for register + // args. + break; + } +#endif + if ((prevArg.GetEarlyNode() != nullptr) && !prevArg.GetEarlyNode()->IsInvariant()) { SetNeedsTemp(&prevArg); @@ -825,6 +834,8 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) } bool treatLikeCall = ((argx->gtFlags & GTF_CALL) != 0); + + ExceptionSetFlags exceptionFlags = ExceptionSetFlags::None; #if FEATURE_FIXED_OUT_ARGS // Like calls, if this argument has a tree that will do an inline throw, // a call to a jit helper, then we need to treat it like a call (but only @@ -833,43 +844,49 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) // conservative, but I want to avoid as much special-case debug-only code // as possible, so leveraging the GTF_CALL flag is the easiest. // - if (!treatLikeCall && (argx->gtFlags & GTF_EXCEPT) && (argCount > 1) && comp->opts.compDbgCode && - (comp->fgWalkTreePre(&argx, Compiler::fgChkThrowCB) == Compiler::WALK_ABORT)) + if (!treatLikeCall && (argx->gtFlags & GTF_EXCEPT) && (argCount > 1) && comp->opts.compDbgCode) { - for (CallArg& otherArg : Args()) + exceptionFlags = comp->gtCollectExceptions(argx); + if ((exceptionFlags & (ExceptionSetFlags::IndexOutOfRangeException | + ExceptionSetFlags::OverflowException)) != ExceptionSetFlags::None) { - if (&otherArg == &arg) + for (CallArg& otherArg : Args()) { - continue; - } + if (&otherArg == &arg) + { + continue; + } - if (otherArg.AbiInfo.GetRegNum() == REG_STK) - { - treatLikeCall = true; - break; + if (otherArg.AbiInfo.GetRegNum() == REG_STK) + { + treatLikeCall = true; + break; + } } } } #endif // FEATURE_FIXED_OUT_ARGS - /* If it contains a call (GTF_CALL) then itself and everything before the call - with a GLOB_EFFECT must eval to temp (this is because everything with SIDE_EFFECT - has to be kept in the right order since we will move the call to the first position) + // If it contains a call (GTF_CALL) then itself and everything before the call + // with a GLOB_EFFECT must eval to temp (this is because everything with SIDE_EFFECT + // has to be kept in the right order since we will move the call to the first position) - For calls we don't have to be quite as conservative as we are with an assignment - since the call won't be modifying any non-address taken LclVars. - */ + // For calls we don't have to be quite as conservative as we are with an assignment + // since the call won't be modifying any non-address taken LclVars. if (treatLikeCall) { - if (argCount > 1) // If this is not the only argument - { - SetNeedsTemp(&arg); - } - else if (varTypeIsFloating(argx->TypeGet()) && (argx->OperGet() == GT_CALL)) + if (canEvalToTemp) { - // Spill all arguments that are floating point calls - SetNeedsTemp(&arg); + if (argCount > 1) // If this is not the only argument + { + SetNeedsTemp(&arg); + } + else if (varTypeIsFloating(argx->TypeGet()) && (argx->OperGet() == GT_CALL)) + { + // Spill all arguments that are floating point calls + SetNeedsTemp(&arg); + } } // All previous arguments may need to be evaluated into temps @@ -880,6 +897,15 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) break; } +#if !FEATURE_FIXED_OUT_ARGS + if (prevArg.AbiInfo.GetRegNum() == REG_STK) + { + // All stack args are already evaluated and placed in order + // in this case. + break; + } +#endif + // For all previous arguments, if they have any GTF_ALL_EFFECT // we require that they be evaluated into a temp if ((prevArg.GetEarlyNode() != nullptr) && ((prevArg.GetEarlyNode()->gtFlags & GTF_ALL_EFFECT) != 0)) @@ -888,8 +914,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) } #if FEATURE_FIXED_OUT_ARGS // Or, if they are stored into the FIXED_OUT_ARG area - // we require that they be moved to the gtCallLateArgs - // and replaced with a placeholder node + // we require that they be moved to the late list else if (prevArg.AbiInfo.GetRegNum() == REG_STK) { prevArg.m_needPlace = true; @@ -903,6 +928,64 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) #endif } } + else if ((argx->gtFlags & GTF_EXCEPT) != 0) + { + // If a previous arg may throw a different exception than this arg + // then we evaluate all previous arguments with GTF_EXCEPT to temps + // to avoid reordering them in our sort later. + if (prevExceptionTree != nullptr) + { + if (prevExceptionFlags == ExceptionSetFlags::None) + { + prevExceptionFlags = comp->gtCollectExceptions(prevExceptionTree); + } + + if (exceptionFlags == ExceptionSetFlags::None) + { + exceptionFlags = comp->gtCollectExceptions(argx); + } + + bool exactlyOne = isPow2(static_cast(exceptionFlags)); + bool throwsSameAsPrev = exactlyOne && (exceptionFlags == prevExceptionFlags); + if (!throwsSameAsPrev) + { + JITDUMP("Exception set for arg [%06u] interferes with previous tree [%06u]; must evaluate previous " + "trees with exceptions to temps\n", + Compiler::dspTreeID(argx), Compiler::dspTreeID(prevExceptionTree)); + + for (CallArg& prevArg : Args()) + { + if (&prevArg == &arg) + { + break; + } + +#if !FEATURE_FIXED_OUT_ARGS + if (prevArg.AbiInfo.GetRegNum() == REG_STK) + { + // All stack args are already evaluated and placed in order + // in this case. + break; + } +#endif + // Invariant here is that all nodes that were not + // already evaluated into temps and that throw can only + // be throwing the same single exception as the + // previous tree, so all of them interfere in the same + // way with the current arg and must be evaluated + // early. + if ((prevArg.GetEarlyNode() != nullptr) && + ((prevArg.GetEarlyNode()->gtFlags & GTF_EXCEPT) != 0)) + { + SetNeedsTemp(&prevArg); + } + } + } + } + + prevExceptionTree = argx; + prevExceptionFlags = exceptionFlags; + } #if FEATURE_MULTIREG_ARGS // For RyuJIT backend we will expand a Multireg arg into a GT_FIELD_LIST @@ -933,25 +1016,10 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) SetNeedsTemp(&arg); } #if defined(FEATURE_SIMD) && defined(TARGET_ARM64) - else if (isMultiRegArg && varTypeIsSIMD(argx->TypeGet())) + else if (isMultiRegArg && varTypeIsSIMD(argx) && (argx->OperIsSimdOrHWintrinsic() || argx->IsCnsVec())) { - GenTree* nodeToCheck = argx; - - if (nodeToCheck->OperIs(GT_OBJ)) - { - nodeToCheck = nodeToCheck->AsObj()->gtOp1; - - if (nodeToCheck->OperIs(GT_ADDR)) - { - nodeToCheck = nodeToCheck->AsOp()->gtOp1; - } - } - - // SIMD types do not need the optimization below due to their sizes - if (nodeToCheck->OperIsSimdOrHWintrinsic() || nodeToCheck->IsCnsVec()) - { - SetNeedsTemp(&arg); - } + // Multi-reg morphing does not handle these SIMD nodes. + SetNeedsTemp(&arg); } #endif #ifndef TARGET_ARM @@ -1122,12 +1190,7 @@ void CallArgs::SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs) { assert(m_argsComplete); -#ifdef DEBUG - if (comp->verbose) - { - printf("\nSorting the arguments:\n"); - } -#endif + JITDUMP("\nSorting the arguments:\n"); // Shuffle the arguments around before we build the late args list. The // idea is to move all "simple" arguments like constants and local vars to @@ -1428,7 +1491,6 @@ GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg) if (varTypeIsStruct(type)) { - #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) // Can this type be passed as a primitive type? @@ -1500,21 +1562,8 @@ GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg) #endif // !(TARGET_ARM64 || TARGET_LOONGARCH64) #endif // FEATURE_MULTIREG_ARGS } - -#else // not (TARGET_AMD64 or TARGET_ARM64 or TARGET_ARM or TARGET_LOONGARCH64) - - // other targets, we pass the struct by value - assert(varTypeIsStruct(type)); - - addrNode = comp->gtNewOperNode(GT_ADDR, TYP_BYREF, argNode); - - // Get a new Obj node temp to use it as a call argument. - // gtNewObjNode will set the GTF_EXCEPT flag if this is not a local stack object. - argNode = comp->gtNewObjNode(comp->lvaGetStruct(tmpVarNum), addrNode); - -#endif // not (TARGET_AMD64 or TARGET_ARM64 or TARGET_ARM or TARGET_LOONGARCH64) - - } // (varTypeIsStruct(type)) +#endif // (TARGET_AMD64 or TARGET_ARM64 or TARGET_ARM or TARGET_LOONGARCH64) + } // (varTypeIsStruct(type)) if (addrNode != nullptr) { @@ -1795,7 +1844,7 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) #ifdef DEBUG if (comp->verbose) { - printf("\nShuffled argument table: "); + printf("\nRegister placement order: "); for (CallArg& arg : LateArgs()) { if (arg.AbiInfo.GetRegNum() != REG_STK) @@ -2107,21 +2156,21 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call size_t addrValue = (size_t)call->gtEntryPoint.addr; GenTree* indirectCellAddress = comp->gtNewIconHandleNode(addrValue, GTF_ICON_FTN_ADDR); -#ifdef DEBUG - indirectCellAddress->AsIntCon()->gtTargetHandle = (size_t)call->gtCallMethHnd; -#endif - indirectCellAddress->SetRegNum(REG_R2R_INDIRECT_PARAM); + INDEBUG(indirectCellAddress->AsIntCon()->gtTargetHandle = (size_t)call->gtCallMethHnd); + #ifdef TARGET_ARM - // Issue #xxxx : Don't attempt to CSE this constant on ARM32 - // - // This constant has specific register requirements, and LSRA doesn't currently correctly - // handle them when the value is in a CSE'd local. + // TODO-ARM: We currently do not properly kill this register in LSRA + // (see getKillSetForCall which does so only for VSD calls). + // We should be able to remove these two workarounds once we do so, + // however when this was tried there were significant regressions. + indirectCellAddress->SetRegNum(REG_R2R_INDIRECT_PARAM); indirectCellAddress->SetDoNotCSE(); -#endif // TARGET_ARM +#endif // Push the stub address onto the list of arguments. - InsertAfterThisOrFirst(comp, - NewCallArg::Primitive(indirectCellAddress).WellKnown(WellKnownArg::R2RIndirectionCell)); + NewCallArg indirCellAddrArg = + NewCallArg::Primitive(indirectCellAddress).WellKnown(WellKnownArg::R2RIndirectionCell); + InsertAfterThisOrFirst(comp, indirCellAddrArg); } #endif @@ -2235,7 +2284,12 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call argx->gtType = TYP_I_IMPL; } - // Setup any HFA information about 'argx' + // Note we must use the signature types for making ABI decisions. This is especially important for structs, + // where the "argx" node can legally have a type that is not ABI-compatible with the one in the signature. + const var_types argSigType = arg.GetSignatureType(); + const CORINFO_CLASS_HANDLE argSigClass = arg.GetSignatureClassHandle(); + + // Setup any HFA information about the argument. bool isHfaArg = false; var_types hfaType = TYP_UNDEF; unsigned hfaSlots = 0; @@ -2247,7 +2301,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call if (GlobalJitOptions::compFeatureHfa) { - hfaType = comp->GetHfaType(argx); + hfaType = comp->GetHfaType(argSigClass); isHfaArg = varTypeIsValidHfaType(hfaType); #if defined(TARGET_ARM64) @@ -2260,7 +2314,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call if (isHfaArg) { - hfaSlots = comp->GetHfaCount(argx); + hfaSlots = comp->GetHfaCount(argSigClass); // If we have a HFA struct it's possible we transition from a method that originally // only had integer types to now start having FP types. We have to communicate this @@ -2274,11 +2328,19 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call const bool isFloatHfa = (hfaType == TYP_FLOAT); #ifdef TARGET_ARM - passUsingFloatRegs = !callIsVararg && (isHfaArg || varTypeUsesFloatReg(argx)) && !comp->opts.compUseSoftFP; + passUsingFloatRegs = + !callIsVararg && (isHfaArg || varTypeUsesFloatReg(argSigType)) && !comp->opts.compUseSoftFP; bool passUsingIntRegs = passUsingFloatRegs ? false : (intArgRegNum < MAX_REG_ARG); - // We don't use the "size" return value from InferOpSizeAlign(). - comp->codeGen->InferOpSizeAlign(argx, &argAlignBytes); + // TODO-Cleanup: use "eeGetArgSizeAlignment" here. See also: https://github.com/dotnet/runtime/issues/46026. + if (varTypeIsStruct(argSigType)) + { + argAlignBytes = comp->info.compCompHnd->getClassAlignmentRequirement(argSigClass); + } + else + { + argAlignBytes = genTypeSize(argSigType); + } argAlignBytes = roundUp(argAlignBytes, TARGET_POINTER_SIZE); @@ -2305,11 +2367,11 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call #elif defined(TARGET_ARM64) assert(!callIsVararg || !isHfaArg); - passUsingFloatRegs = !callIsVararg && (isHfaArg || varTypeUsesFloatReg(argx)); + passUsingFloatRegs = !callIsVararg && (isHfaArg || varTypeUsesFloatReg(argSigType)); #elif defined(TARGET_AMD64) - passUsingFloatRegs = varTypeIsFloating(argx); + passUsingFloatRegs = varTypeIsFloating(argSigType); #elif defined(TARGET_X86) @@ -2318,7 +2380,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call #elif defined(TARGET_LOONGARCH64) assert(!callIsVararg && !isHfaArg); - passUsingFloatRegs = varTypeUsesFloatReg(argx); + passUsingFloatRegs = varTypeUsesFloatReg(argSigType); DWORD floatFieldFlags = STRUCT_NO_FLOAT_FIELD; #else @@ -2327,73 +2389,44 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call bool isBackFilled = false; unsigned nextFltArgRegNum = fltArgRegNum; // This is the next floating-point argument register number to use + bool isStructArg = varTypeIsStruct(argSigType); var_types structBaseType = TYP_STRUCT; unsigned structSize = 0; bool passStructByRef = false; - bool isStructArg; - GenTree* actualArg = argx->gtEffectiveVal(true /* Commas only */); - // // Figure out the size of the argument. This is either in number of registers, or number of // TARGET_POINTER_SIZE stack slots, or the sum of these if the argument is split between the registers and // the stack. // - isStructArg = varTypeIsStruct(argx); - // Note that we internally in the JIT can change some struct args to - // primitive args (e.g. OBJ(x) -> IND(x)). Similarly, - // the ABI type can also change from struct to primitive (e.g. a 8-byte - // struct passed in a register). So isStructArg may be false even if - // the signature type was (or is) a struct, however only in cases where - // it does not matter. - CORINFO_CLASS_HANDLE objClass = NO_CLASS_HANDLE; + if (isStructArg) { - objClass = comp->gtGetStructHandle(argx); - if (argx->TypeGet() == TYP_STRUCT) - { - // For TYP_STRUCT arguments we must have an OBJ, LCL_VAR or MKREFANY - switch (actualArg->OperGet()) - { - case GT_OBJ: - structSize = actualArg->AsObj()->GetLayout()->GetSize(); - assert(structSize == comp->info.compCompHnd->getClassSize(objClass)); - break; - case GT_LCL_VAR: - structSize = comp->lvaGetDesc(actualArg->AsLclVarCommon())->lvExactSize; - break; - case GT_MKREFANY: - structSize = comp->info.compCompHnd->getClassSize(objClass); - break; - default: - BADCODE("illegal argument tree: cannot determine size for ABI handling"); - break; - } - } - else - { - structSize = genTypeSize(argx); - assert(structSize == comp->info.compCompHnd->getClassSize(objClass)); - } + GenTree* actualArg = argx->gtEffectiveVal(true /* Commas only */); + + // Here we look at "actualArg" to avoid calling "getClassSize". + structSize = actualArg->TypeIs(TYP_STRUCT) ? actualArg->GetLayout(comp)->GetSize() : genTypeSize(actualArg); + + assert(structSize == comp->info.compCompHnd->getClassSize(argSigClass)); } #if defined(TARGET_AMD64) #ifdef UNIX_AMD64_ABI if (!isStructArg) { size = 1; // On AMD64, all primitives fit in a single (64-bit) 'slot' - byteSize = genTypeSize(arg.GetSignatureType()); + byteSize = genTypeSize(argSigType); } else { size = (unsigned)(roundUp(structSize, TARGET_POINTER_SIZE)) / TARGET_POINTER_SIZE; byteSize = structSize; - comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(objClass, &structDesc); + comp->eeGetSystemVAmd64PassStructInRegisterDescriptor(argSigClass, &structDesc); } #else // !UNIX_AMD64_ABI size = 1; // On AMD64 Windows, all args fit in a single (64-bit) 'slot' if (!isStructArg) { - byteSize = genTypeSize(arg.GetSignatureType()); + byteSize = genTypeSize(argSigType); } #endif // UNIX_AMD64_ABI @@ -2404,9 +2437,8 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call { // HFA structs are passed by value in multiple registers. // The "size" in registers may differ the size in pointer-sized units. - CORINFO_CLASS_HANDLE structHnd = comp->gtGetStructHandle(argx); - size = comp->GetHfaCount(structHnd); - byteSize = comp->info.compCompHnd->getClassSize(structHnd); + size = hfaSlots; + byteSize = structSize; } else { @@ -2422,13 +2454,13 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call size = 1; } } - // Note that there are some additional rules for multireg structs. + // Note that there are some additional rules for multireg structs on ARM64. // (i.e they cannot be split between registers and the stack) } else { size = 1; // Otherwise, all primitive types fit in a single (64-bit) 'slot' - byteSize = genTypeSize(arg.GetSignatureType()); + byteSize = genTypeSize(argSigType); } #elif defined(TARGET_ARM) || defined(TARGET_X86) if (isStructArg) @@ -2440,8 +2472,8 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call { // The typical case. // Long/double type argument(s) will be modified as needed in Lowering. - size = genTypeStSz(argx->gtType); - byteSize = genTypeSize(arg.GetSignatureType()); + size = genTypeStSz(argSigType); + byteSize = genTypeSize(argSigType); } #else #error Unsupported or unset target architecture @@ -2453,14 +2485,14 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call assert(structSize != 0); Compiler::structPassingKind howToPassStruct; - structBaseType = comp->getArgTypeForStruct(objClass, &howToPassStruct, callIsVararg, structSize); + structBaseType = comp->getArgTypeForStruct(argSigClass, &howToPassStruct, callIsVararg, structSize); passStructByRef = (howToPassStruct == Compiler::SPK_ByReference); #if defined(TARGET_LOONGARCH64) if (!passStructByRef) { assert((howToPassStruct == Compiler::SPK_ByValue) || (howToPassStruct == Compiler::SPK_PrimitiveType)); - floatFieldFlags = comp->info.compCompHnd->getLoongArch64PassStructInRegisterFlags(objClass); + floatFieldFlags = comp->info.compCompHnd->getLoongArch64PassStructInRegisterFlags(argSigClass); passUsingFloatRegs = (floatFieldFlags & STRUCT_HAS_FLOAT_FIELDS_MASK) ? true : false; comp->compFloatingPointUsed |= passUsingFloatRegs; @@ -2471,8 +2503,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call // for "struct { float, float }", and retyping to a primitive here will cause the // multi-reg morphing to not kick in (the struct in question needs to be passed in // two FP registers). Here is just keep "structBaseType" as "TYP_STRUCT". - // TODO-LoongArch64: fix "getPrimitiveTypeForStruct" or use the ABI information in - // the arg entry instead of calling it here. + // TODO-LoongArch64: fix "getPrimitiveTypeForStruct". structBaseType = TYP_STRUCT; } @@ -2531,7 +2562,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call // Arm64 Apple has a special ABI for passing small size arguments on stack, // bytes are aligned to 1-byte, shorts to 2-byte, int/float to 4-byte, etc. // It means passing 8 1-byte arguments on stack can take as small as 8 bytes. - argAlignBytes = comp->eeGetArgSizeAlignment(arg.GetSignatureType(), isFloatHfa); + argAlignBytes = comp->eeGetArgSizeAlignment(argSigType, isFloatHfa); } #ifdef TARGET_LOONGARCH64 @@ -2543,11 +2574,11 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call bool isRegArg = false; regNumber nonStdRegNum = REG_NA; - if (isRegParamType(genActualType(argx->TypeGet())) + if (isRegParamType(genActualType(argSigType)) #ifdef UNIX_AMD64_ABI && (!isStructArg || structDesc.passedInRegisters) #elif defined(TARGET_X86) - || (isStructArg && comp->isTrivialPointerSizedStruct(objClass)) + || (isStructArg && comp->isTrivialPointerSizedStruct(argSigClass)) #endif ) { @@ -3003,12 +3034,9 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call #endif } - if (GlobalJitOptions::compFeatureHfa) + if (isHfaArg) { - if (isHfaArg) - { - arg.AbiInfo.SetHfaType(hfaType, hfaSlots); - } + arg.AbiInfo.SetHfaType(hfaType, hfaSlots); } arg.AbiInfo.SetMultiRegNums(); @@ -3199,15 +3227,8 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) unsigned originalSize; if (argObj->TypeGet() == TYP_STRUCT) { - if (argObj->OperIs(GT_OBJ)) - { - originalSize = argObj->AsObj()->Size(); - } - else - { - // Must be LCL_VAR: we have a BADCODE assert for this in AddFinalArgsAndDetermineABIInfo. - originalSize = lvaGetDesc(argObj->AsLclVar())->lvExactSize; - } + assert(argObj->OperIs(GT_OBJ, GT_LCL_VAR, GT_LCL_FLD)); + originalSize = argObj->GetLayout(this)->GetSize(); } else { @@ -3408,13 +3429,28 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) makeOutArgCopy = true; } } - else if (genTypeSize(varDsc->TypeGet()) != genTypeSize(structBaseType)) + else if (genTypeSize(varDsc) != genTypeSize(structBaseType)) { // Not a promoted struct, so just swizzle the type by using GT_LCL_FLD lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::SwizzleArg)); argObj->ChangeOper(GT_LCL_FLD); argObj->gtType = structBaseType; } + else if (varTypeUsesFloatReg(varDsc) != varTypeUsesFloatReg(structBaseType)) + { + // Here we can see int <-> float, long <-> double, long <-> simd8 mismatches, due + // to the "OBJ(ADDR(LCL))" => "LCL" folding above. The latter case is handled in + // lowering, others we will handle here via swizzling. + CLANG_FORMAT_COMMENT_ANCHOR; +#ifdef TARGET_AMD64 + if (varDsc->TypeGet() != TYP_SIMD8) +#endif // TARGET_AMD64 + { + lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::SwizzleArg)); + argObj->ChangeOper(GT_LCL_FLD); + argObj->gtType = structBaseType; + } + } } else if (argObj->OperIs(GT_LCL_FLD, GT_IND)) { @@ -3437,36 +3473,6 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) assert(varTypeIsEnregisterable(argObj->TypeGet()) || (makeOutArgCopy && varTypeIsEnregisterable(structBaseType))); } - -#if !defined(UNIX_AMD64_ABI) && !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) - // TODO-CQ-XARCH: there is no need for a temp copy if we improve our code generation in - // `genPutStructArgStk` for xarch like we did it for Arm/Arm64. - - // We still have a struct unless we converted the GT_OBJ into a GT_IND above... - if (isHfaArg && passUsingFloatRegs) - { - } - else if (structBaseType == TYP_STRUCT) - { - // If the valuetype size is not a multiple of TARGET_POINTER_SIZE, - // we must copyblk to a temp before doing the obj to avoid - // the obj reading memory past the end of the valuetype - if (roundupSize > originalSize) - { - makeOutArgCopy = true; - - // There are a few special cases where we can omit using a CopyBlk - // where we normally would need to use one. - - if (argObj->OperIs(GT_OBJ) && - argObj->AsObj()->gtGetOp1()->IsLocalAddrExpr() != nullptr) // Is the source a LclVar? - { - makeOutArgCopy = false; - } - } - } - -#endif // !UNIX_AMD64_ABI } } @@ -3800,15 +3806,15 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) #if FEATURE_MULTIREG_ARGS // Examine 'arg' and setup argValue objClass and structSize // - const CORINFO_CLASS_HANDLE objClass = gtGetStructHandle(argNode); - GenTree* argValue = argNode; // normally argValue will be arg, but see right below - unsigned structSize = 0; + GenTree* argValue = argNode; // normally argValue will be arg, but see right below + ClassLayout* layout = nullptr; + unsigned structSize = 0; if (argNode->OperGet() == GT_OBJ) { - GenTreeObj* argObj = argNode->AsObj(); - ClassLayout* objLayout = argObj->GetLayout(); - structSize = objLayout->GetSize(); + GenTreeObj* argObj = argNode->AsObj(); + layout = argObj->GetLayout(); + structSize = layout->GetSize(); // If we have a GT_OBJ of a GT_ADDR then we set argValue to the child node of the GT_ADDR. // TODO-ADDR: always perform this transformation in local morph and delete this code. @@ -3820,36 +3826,31 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) if (location->OperIsLocalRead()) { if (!location->OperIs(GT_LCL_VAR) || - !ClassLayout::AreCompatible(lvaGetDesc(location->AsLclVarCommon())->GetLayout(), objLayout)) + !ClassLayout::AreCompatible(lvaGetDesc(location->AsLclVarCommon())->GetLayout(), layout)) { unsigned lclOffset = location->AsLclVarCommon()->GetLclOffs(); location->ChangeType(argObj->TypeGet()); location->SetOper(GT_LCL_FLD); location->AsLclFld()->SetLclOffs(lclOffset); - location->AsLclFld()->SetLayout(objLayout); + location->AsLclFld()->SetLayout(layout); } argValue = location; } } } - else if (argNode->OperGet() == GT_LCL_VAR) - { - LclVarDsc* varDsc = lvaGetDesc(argNode->AsLclVarCommon()); - structSize = varDsc->lvExactSize; - } - else if (!argNode->TypeIs(TYP_STRUCT)) + else if (argNode->TypeIs(TYP_STRUCT)) { - structSize = genTypeSize(argNode); + assert(argNode->OperIsLocalRead()); + layout = argNode->AsLclVarCommon()->GetLayout(this); + structSize = layout->GetSize(); } else { - structSize = info.compCompHnd->getClassSize(objClass); + structSize = genTypeSize(argNode); } - assert(structSize == info.compCompHnd->getClassSize(objClass)); - struct ArgElem { var_types Type; // The type to load into the register (can be small). @@ -3873,8 +3874,11 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) else { assert(structSize <= MAX_ARG_REG_COUNT * TARGET_POINTER_SIZE); - BYTE gcPtrs[MAX_ARG_REG_COUNT]; - info.compCompHnd->getClassGClayout(objClass, &gcPtrs[0]); + assert((layout != nullptr) || varTypeIsSIMD(argValue)); + + auto getSlotType = [layout](unsigned inx) { + return (layout != nullptr) ? layout->GetGCPtrType(inx) : TYP_I_IMPL; + }; // Here, we will set the sizes "rounded up" and then adjust the type of the last element below. for (unsigned inx = 0, offset = 0; inx < elemCount; inx++) @@ -3882,7 +3886,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) elems[inx].Offset = offset; #if defined(UNIX_AMD64_ABI) - if (gcPtrs[inx] == TYPE_GC_NONE) + if (!varTypeIsGC(getSlotType(inx))) { elems[inx].Type = GetTypeFromClassificationAndSizes(arg->AbiInfo.StructDesc.eightByteClassifications[inx], @@ -3899,7 +3903,7 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) else #endif // TARGET_LOONGARCH64 { - elems[inx].Type = getJitGCType(gcPtrs[inx]); + elems[inx].Type = getSlotType(inx); offset += TARGET_POINTER_SIZE; } } @@ -4053,11 +4057,10 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg) } else { - assert(argValue->OperIs(GT_OBJ)); + assert(argValue->OperIsIndir()); - GenTreeObj* argObj = argValue->AsObj(); - GenTree* baseAddr = argObj->Addr(); - var_types addrType = baseAddr->TypeGet(); + GenTree* baseAddr = argValue->AsIndir()->Addr(); + var_types addrType = baseAddr->TypeGet(); // TODO-ADDR: make sure all such OBJs are transformed into TYP_STRUCT LCL_FLDs and delete this condition. GenTreeLclVarCommon* lclSrcNode = baseAddr->IsLocalAddrExpr(); @@ -4158,7 +4161,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) // // We don't need a copy if this is the last use of an implicit by-ref local. // - if (opts.OptimizationEnabled()) + if (opts.OptimizationEnabled() && arg->AbiInfo.PassedByRef) { GenTreeLclVar* const lcl = argx->IsImplicitByrefParameterValue(this); @@ -4220,7 +4223,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) { tmp = (unsigned)lclNum; found = true; - JITDUMP("reusing outgoing struct arg"); + JITDUMP("reusing outgoing struct arg\n"); break; } } @@ -4267,7 +4270,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) // When on Unix create LCL_FLD for structs passed in more than one registers. See fgMakeTmpArgNode GenTree* argNode = copyBlk; -#else // FEATURE_FIXED_OUT_ARGS +#else // !FEATURE_FIXED_OUT_ARGS // Structs are always on the stack, and thus never need temps // so we have to put the copy and temp all into one expression. @@ -4276,7 +4279,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) // Change the expression to "(tmp=val),tmp" argNode = gtNewOperNode(GT_COMMA, argNode->TypeGet(), copyBlk, argNode); -#endif // FEATURE_FIXED_OUT_ARGS +#endif // !FEATURE_FIXED_OUT_ARGS arg->SetEarlyNode(argNode); } @@ -4642,10 +4645,11 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr) // Likewise, allocate a temporary if the expression is a GT_LCL_FLD node. These used to be created // after fgMorphIndexAddr from GT_FIELD trees so this preserves the existing behavior. This is // perhaps a decision that should be left to CSE but FX diffs show that it is slightly better to - // do this here. + // do this here. Likewise for implicit byrefs. - if ((arrRef->gtFlags & (GTF_ASG | GTF_CALL | GTF_GLOB_REF)) || - gtComplexityExceeds(&arrRef, MAX_ARR_COMPLEXITY) || arrRef->OperIs(GT_FIELD, GT_LCL_FLD)) + if (((arrRef->gtFlags & (GTF_ASG | GTF_CALL | GTF_GLOB_REF)) != 0) || + gtComplexityExceeds(&arrRef, MAX_ARR_COMPLEXITY) || arrRef->OperIs(GT_FIELD, GT_LCL_FLD) || + (arrRef->OperIs(GT_LCL_VAR) && lvaIsLocalImplicitlyAccessedByRef(arrRef->AsLclVar()->GetLclNum()))) { unsigned arrRefTmpNum = lvaGrabTemp(true DEBUGARG("arr expr")); arrRefDefn = gtNewTempAssign(arrRefTmpNum, arrRef); @@ -4658,8 +4662,9 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr) noway_assert(arrRef2 != nullptr); } - if ((index->gtFlags & (GTF_ASG | GTF_CALL | GTF_GLOB_REF)) || gtComplexityExceeds(&index, MAX_ARR_COMPLEXITY) || - index->OperIs(GT_FIELD, GT_LCL_FLD)) + if (((index->gtFlags & (GTF_ASG | GTF_CALL | GTF_GLOB_REF)) != 0) || + gtComplexityExceeds(&index, MAX_ARR_COMPLEXITY) || index->OperIs(GT_FIELD, GT_LCL_FLD) || + (index->OperIs(GT_LCL_VAR) && lvaIsLocalImplicitlyAccessedByRef(index->AsLclVar()->GetLclNum()))) { unsigned indexTmpNum = lvaGrabTemp(true DEBUGARG("index expr")); indexDefn = gtNewTempAssign(indexTmpNum, index); @@ -4765,8 +4770,8 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr) // we at least will be able to hoist/CSE "index + elemOffset" in some cases. // See https://github.com/dotnet/runtime/pull/61293#issuecomment-964146497 - // Use 2) form only for primitive types for now - it significantly reduced number of size regressions - if (!varTypeIsIntegral(elemTyp) && !varTypeIsFloating(elemTyp)) + // Don't use 2) for structs to reduce number of size regressions + if (varTypeIsStruct(elemTyp)) { groupArrayRefWithElemOffset = false; } @@ -4847,11 +4852,15 @@ GenTree* Compiler::fgMorphLocal(GenTreeLclVarCommon* lclNode) GenTree* expandedTree = nullptr; #ifdef TARGET_X86 expandedTree = fgMorphExpandStackArgForVarArgs(lclNode); -#endif // TARGET_X86 +#else + expandedTree = fgMorphExpandImplicitByRefArg(lclNode); +#endif if (expandedTree != nullptr) { - return fgMorphTree(expandedTree); + expandedTree = fgMorphTree(expandedTree); + DBEXEC(expandedTree == lclNode, expandedTree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED); + return expandedTree; } if (lclNode->OperIsLocalAddr()) @@ -4928,6 +4937,116 @@ GenTree* Compiler::fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode) } #endif +//------------------------------------------------------------------------ +// fgMorphExpandImplicitByRefArg: Morph an implicit by-ref parameter. +// +// Arguments: +// lclNode - The local node to morph +// +// Return Value: +// The expanded tree for "lclNode", which the caller is expected to +// morph further. +// +GenTree* Compiler::fgMorphExpandImplicitByRefArg(GenTreeLclVarCommon* lclNode) +{ + if (!fgGlobalMorph) + { + return nullptr; + } + + unsigned lclNum = lclNode->GetLclNum(); + LclVarDsc* varDsc = lvaGetDesc(lclNum); + unsigned fieldOffset = 0; + unsigned newLclNum = BAD_VAR_NUM; + + if (lvaIsImplicitByRefLocal(lclNum)) + { + // The SIMD transformation to coalesce contiguous references to SIMD vector fields will re-invoke + // the traversal to mark address-taken locals. So, we may encounter a tree that has already been + // transformed to TYP_BYREF. If we do, leave it as-is. + if (lclNode->OperIs(GT_LCL_VAR) && lclNode->TypeIs(TYP_BYREF)) + { + return nullptr; + } + + if (varDsc->lvPromoted) + { + // fgRetypeImplicitByRefArgs created a new promoted struct local to represent this arg. + // Rewrite the node to refer to it. + assert(varDsc->lvFieldLclStart != 0); + + lclNode->SetLclNum(varDsc->lvFieldLclStart); + return lclNode; + } + + newLclNum = lclNum; + } + else if (varDsc->lvIsStructField && lvaIsImplicitByRefLocal(varDsc->lvParentLcl)) + { + // This was a field reference to an implicit-by-reference struct parameter that was + // dependently promoted. + newLclNum = varDsc->lvParentLcl; + fieldOffset = varDsc->lvFldOffset; + } + else + { + return nullptr; + } + + // Add a level of indirection to this node. The "base" will be a local node referring to "newLclNum". + // We will also add an offset, and, if the original "lclNode" represents a location, a dereference. + bool isAddress = lclNode->OperIsLocalAddr(); + unsigned offset = lclNode->GetLclOffs() + fieldOffset; + var_types argNodeType = lclNode->TypeGet(); + ClassLayout* argNodeLayout = nullptr; + if (varTypeIsStruct(argNodeType)) + { + argNodeLayout = lclNode->GetLayout(this); + } + + JITDUMP("\nRewriting an implicit by-ref parameter %s:\n", isAddress ? "address" : "reference"); + DISPTREE(lclNode); + + lclNode->ChangeType(TYP_BYREF); + lclNode->ChangeOper(GT_LCL_VAR); + lclNode->SetLclNum(newLclNum); + lclNode->SetAllEffectsFlags(GTF_EMPTY); // Implicit by-ref parameters cannot be address-exposed. + + GenTree* addrNode = lclNode; + if (offset != 0) + { + addrNode = gtNewOperNode(GT_ADD, TYP_BYREF, addrNode, gtNewIconNode(offset, TYP_I_IMPL)); + } + + GenTree* newArgNode; + if (!isAddress) + { + if (varTypeIsStruct(argNodeType)) + { + newArgNode = gtNewObjNode(argNodeLayout, addrNode); + } + else + { + newArgNode = gtNewIndir(argNodeType, addrNode); + } + + // Currently, we have to conservatively treat all indirections off of implicit byrefs as + // global. This is because we lose the information on whether the original local's address + // was exposed when we retype it in "fgRetypeImplicitByRefArgs". + newArgNode->gtFlags |= GTF_GLOB_REF; + } + else + { + newArgNode = addrNode; + } + + JITDUMP("Transformed into:\n"); + DISPTREE(newArgNode); + JITDUMP("\n"); + + return newArgNode; +} + /***************************************************************************** * * Transform the given GT_LCL_VAR tree for code generation. @@ -5036,21 +5155,12 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) CORINFO_FIELD_HANDLE symHnd = tree->AsField()->gtFldHnd; unsigned fldOffset = tree->AsField()->gtFldOffset; GenTree* objRef = tree->AsField()->GetFldObj(); - bool objIsLocal = false; bool fldMayOverlap = tree->AsField()->gtFldMayOverlap; FieldSeqNode* fieldSeq = FieldSeqStore::NotAField(); // Reset the flag because we may reuse the node. tree->AsField()->gtFldMayOverlap = false; - if (fgGlobalMorph && (objRef != nullptr) && (objRef->gtOper == GT_ADDR)) - { - // Make sure we've checked if 'objRef' is an address of an implicit-byref parameter. - // If it is, fgMorphImplicitByRefArgs may change it do a different opcode, which the - // simd field rewrites are sensitive to. - fgMorphImplicitByRefArgs(objRef); - } - noway_assert(((objRef != nullptr) && (objRef->IsLocalAddrExpr() != nullptr)) || ((tree->gtFlags & GTF_GLOB_REF) != 0)); @@ -5082,13 +5192,9 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) // before it is used. MorphAddrContext defMAC(MACK_Ind); - /* Is this an instance data member? */ - - if (objRef) + // Is this an instance data member? + if (objRef != nullptr) { - GenTree* addr; - objIsLocal = objRef->IsLocal(); - if (tree->gtFlags & GTF_IND_TLS_REF) { NO_WAY("instance field can not be a TLS ref."); @@ -5167,8 +5273,8 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) */ var_types objRefType = objRef->TypeGet(); - - GenTree* comma = nullptr; + GenTree* addr = nullptr; + GenTree* comma = nullptr; // NULL mac means we encounter the GT_FIELD first. This denotes a dereference of the field, // and thus is equivalent to a MACK_Ind with zero offset. @@ -5243,11 +5349,10 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) // Create the "comma" subtree // GenTree* asg = nullptr; - GenTree* nullchk; unsigned lclNum; - if (objRef->gtOper != GT_LCL_VAR) + if (!objRef->OperIs(GT_LCL_VAR) || lvaIsLocalImplicitlyAccessedByRef(objRef->AsLclVar()->GetLclNum())) { lclNum = fgGetBigOffsetMorphingTemp(genActualType(objRef->TypeGet())); @@ -5259,17 +5364,13 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) lclNum = objRef->AsLclVarCommon()->GetLclNum(); } - GenTree* lclVar = gtNewLclvNode(lclNum, objRefType); - nullchk = gtNewNullCheck(lclVar, compCurBB); + GenTree* lclVar = gtNewLclvNode(lclNum, objRefType); + GenTree* nullchk = gtNewNullCheck(lclVar, compCurBB); - if (asg) + if (asg != nullptr) { // Create the "comma" node. - comma = gtNewOperNode(GT_COMMA, - TYP_VOID, // We don't want to return anything from this "comma" node. - // Set the type to TYP_VOID, so we can select "cmp" instruction - // instead of "mov" instruction later on. - asg, nullchk); + comma = gtNewOperNode(GT_COMMA, TYP_VOID, asg, nullchk); } else { @@ -5494,7 +5595,8 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac) { handleKind = GTF_ICON_STATIC_HDL; } - GenTree* addr = gtNewIconHandleNode((size_t)fldAddr, handleKind, fieldSeq); + GenTreeIntCon* addr = gtNewIconHandleNode((size_t)fldAddr, handleKind, fieldSeq); + INDEBUG(addr->gtTargetHandle = reinterpret_cast(symHnd)); // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS, if we need to. if (((tree->gtFlags & GTF_FLD_INITCLASS) != 0) && !isStaticReadOnlyInited) @@ -6649,9 +6751,11 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) (call->gtCallType == CT_USER_FUNC) ? call->gtCallMethHnd : nullptr, call->IsTailPrefixedCall(), tailCallResult, nullptr); - // Are we currently planning to expand the gtControlExpr as an early virtual call target? + // Do some profitability checks for whether we should expand a vtable call + // target early. Note that we may already have expanded it due to GDV at + // this point, so make sure we do not undo that work. // - if (call->IsExpandedEarly() && call->IsVirtualVtable()) + if (call->IsExpandedEarly() && call->IsVirtualVtable() && (call->gtControlExpr == nullptr)) { assert(call->gtArgs.HasThisPointer()); // It isn't alway profitable to expand a virtual call early @@ -7918,7 +8022,7 @@ void Compiler::fgMorphTailCallViaJitHelper(GenTreeCall* call) // call - a call that needs virtual stub dispatching. // // Return Value: -// addr tree with set resister requirements. +// addr tree // GenTree* Compiler::fgGetStubAddrArg(GenTreeCall* call) { @@ -7933,12 +8037,9 @@ GenTree* Compiler::fgGetStubAddrArg(GenTreeCall* call) assert(call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT); ssize_t addr = ssize_t(call->gtStubCallStubAddr); stubAddrArg = gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR); -#ifdef DEBUG - stubAddrArg->AsIntCon()->gtTargetHandle = (size_t)call->gtCallMethHnd; -#endif + INDEBUG(stubAddrArg->AsIntCon()->gtTargetHandle = (size_t)call->gtCallMethHnd); } assert(stubAddrArg != nullptr); - stubAddrArg->SetRegNum(virtualStubParamInfo->GetReg()); return stubAddrArg; } @@ -8425,18 +8526,18 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) // if (call->IsExpandedEarly() && call->IsVirtualVtable()) { - // We only expand the Vtable Call target once in the global morph phase - if (fgGlobalMorph) + // We expand the Vtable Call target either in the global morph phase or + // in guarded devirt if we need it for the guard. + if (fgGlobalMorph && (call->gtControlExpr == nullptr)) { - assert(call->gtControlExpr == nullptr); // We only call this method and assign gtControlExpr once call->gtControlExpr = fgExpandVirtualVtableCallTarget(call); } // We always have to morph or re-morph the control expr // call->gtControlExpr = fgMorphTree(call->gtControlExpr); - // Propagate any gtFlags into the call - call->gtFlags |= call->gtControlExpr->gtFlags; + // Propagate any side effect flags into the call + call->gtFlags |= call->gtControlExpr->gtFlags & GTF_ALL_EFFECT; } // Morph stelem.ref helper call to store a null value, into a store into an array without the helper. @@ -8822,7 +8923,8 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree) // target of a Delegate or a raw function pointer. bool isUnsafeFunctionPointer = !fptrValTree->gtFptrDelegateTarget; - CORINFO_CONST_LOOKUP addrInfo; + CORINFO_CONST_LOOKUP addrInfo; + CORINFO_METHOD_HANDLE funcHandle = fptrValTree->gtFptrMethod; #ifdef FEATURE_READYTORUN if (fptrValTree->gtEntryPoint.addr != nullptr) @@ -8832,7 +8934,7 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree) else #endif { - info.compCompHnd->getFunctionFixedEntryPoint(fptrValTree->gtFptrMethod, isUnsafeFunctionPointer, &addrInfo); + info.compCompHnd->getFunctionFixedEntryPoint(funcHandle, isUnsafeFunctionPointer, &addrInfo); } GenTree* indNode = nullptr; @@ -8851,6 +8953,7 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree) case IAT_PVALUE: indNode = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)addrInfo.handle, GTF_ICON_FTN_ADDR, true); + INDEBUG(indNode->gtGetOp1()->AsIntCon()->gtTargetHandle = reinterpret_cast(funcHandle)); break; case IAT_VALUE: @@ -8859,6 +8962,7 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree) tree->SetOper(GT_CNS_INT); tree->AsIntConCommon()->SetIconValue(ssize_t(addrInfo.handle)); tree->gtFlags |= GTF_ICON_FTN_ADDR; + INDEBUG(tree->AsIntCon()->gtTargetHandle = reinterpret_cast(funcHandle)); break; default: @@ -9621,6 +9725,11 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, ClassLa { lclNode = effectiveVal->AsLclVarCommon(); } + else if (effectiveVal->OperIs(GT_LCL_FLD)) + { + needsIndirection = false; + assert(ClassLayout::AreCompatible(effectiveVal->AsLclFld()->GetLayout(), blockLayout)); + } else if (effectiveVal->IsCall()) { needsIndirection = false; @@ -9869,7 +9978,7 @@ GenTree* Compiler::fgMorphFieldToSimdGetElement(GenTree* tree) var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); GenTree* op2 = gtNewIconNode(index, TYP_INT); - assert(simdSize <= 16); + assert(simdSize <= 32); assert(simdSize >= ((index + 1) * genTypeSize(simdBaseType))); #if defined(TARGET_XARCH) @@ -9944,7 +10053,7 @@ GenTree* Compiler::fgMorphFieldAssignToSimdSetElement(GenTree* tree) var_types simdType = simdStructNode->gtType; var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); - assert(simdSize <= 16); + assert(simdSize <= 32); assert(simdSize >= ((index + 1) * genTypeSize(simdBaseType))); GenTree* op2 = gtNewIconNode(index, TYP_INT); @@ -9960,18 +10069,6 @@ GenTree* Compiler::fgMorphFieldAssignToSimdSetElement(GenTree* tree) tree->AsOp()->gtOp1 = target; tree->AsOp()->gtOp2 = simdTree; - // fgMorphTree has already called fgMorphImplicitByRefArgs() on this assignment, but the source - // and target have not yet been morphed. - // Therefore, in case the source and/or target are now implicit byrefs, we need to call it again. - if (fgMorphImplicitByRefArgs(tree)) - { - if (tree->gtGetOp1()->OperIsBlk()) - { - assert(tree->gtGetOp1()->TypeGet() == simdType); - tree->gtGetOp1()->SetOper(GT_IND); - tree->gtGetOp1()->gtType = simdType; - } - } #ifdef DEBUG tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED; #endif @@ -10284,22 +10381,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) case GT_MUL: noway_assert(op2 != nullptr); - if (opts.OptimizationEnabled() && !optValnumCSE_phase && !tree->gtOverflow()) - { - // MUL(NEG(a), C) => MUL(a, NEG(C)) - if (op1->OperIs(GT_NEG) && !op1->gtGetOp1()->IsCnsIntOrI() && op2->IsCnsIntOrI() && - !op2->IsIconHandle()) - { - GenTree* newOp1 = op1->gtGetOp1(); - GenTree* newConst = gtNewIconNode(-op2->AsIntCon()->IconValue(), op2->TypeGet()); - DEBUG_DESTROY_NODE(op1); - DEBUG_DESTROY_NODE(op2); - tree->AsOp()->gtOp1 = newOp1; - tree->AsOp()->gtOp2 = newConst; - return fgMorphSmpOp(tree, mac); - } - } - #ifndef TARGET_64BIT if (typ == TYP_LONG) { @@ -10560,10 +10641,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) #ifdef TARGET_ARM64 // ARM64 architecture manual suggests this transformation // for the mod operator. - // However, we do skip this optimization for ARM64 if the second operand - // is an integral constant power of 2 because there is an even better - // optimization in lowering that is specific for ARM64. - else if (!(tree->OperIs(GT_MOD) && op2->IsIntegralConstPow2())) + else #else // XARCH only applies this transformation if we know // that magic division will be used - which is determined @@ -11213,9 +11291,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) */ GenTree* temp; - size_t ival1; GenTree* lclVarTree; - GenTree* effectiveOp1; FieldSeqNode* fieldSeq = nullptr; switch (oper) @@ -11235,28 +11311,14 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) lclVarTree->gtFlags |= GTF_VAR_DEF; } - effectiveOp1 = op1->gtEffectiveVal(); - - // If we are storing a small type, we might be able to omit a cast. - if ((effectiveOp1->OperIs(GT_IND) || - (effectiveOp1->OperIs(GT_LCL_VAR) && - lvaGetDesc(effectiveOp1->AsLclVarCommon()->GetLclNum())->lvNormalizeOnLoad())) && - varTypeIsSmall(effectiveOp1)) + if (op2->OperIs(GT_CAST)) { - if (!gtIsActiveCSE_Candidate(op2) && op2->OperIs(GT_CAST) && - varTypeIsIntegral(op2->AsCast()->CastOp()) && !op2->gtOverflow()) - { - var_types castType = op2->CastToType(); + tree = fgOptimizeCastOnAssignment(tree->AsOp()); - // If we are performing a narrowing cast and - // castType is larger or the same as op1's type - // then we can discard the cast. + assert(tree->OperIs(GT_ASG)); - if (varTypeIsSmall(castType) && (genTypeSize(castType) >= genTypeSize(effectiveOp1))) - { - tree->AsOp()->gtOp2 = op2 = op2->AsCast()->CastOp(); - } - } + op1 = tree->gtGetOp1(); + op2 = tree->gtGetOp2(); } fgAssignSetVarDef(tree); @@ -11323,6 +11385,21 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) assert(op2 == tree->AsOp()->gtGetOp2()); } + if (opts.OptimizationEnabled() && fgGlobalMorph) + { + if (op2->IsIntegralConst() || op1->IsIntegralConst()) + { + if (tree->OperIs(GT_GT, GT_LT, GT_LE, GT_GE)) + { + tree = fgOptimizeRelationalComparisonWithFullRangeConst(tree->AsOp()); + if (tree->OperIs(GT_CNS_INT)) + { + return tree; + } + } + } + } + COMPARE: noway_assert(tree->OperIsCompare()); @@ -11590,15 +11667,14 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) bool foldAndReturnTemp = false; temp = nullptr; - ival1 = 0; // Don't remove a volatile GT_IND, even if the address points to a local variable. - if ((tree->gtFlags & GTF_IND_VOLATILE) == 0) + // + if (!tree->AsIndir()->IsVolatile()) { /* Try to Fold *(&X) into X */ if (op1->gtOper == GT_ADDR) { - // Can not remove a GT_ADDR if it is currently a CSE candidate. if (gtIsActiveCSE_Candidate(op1)) { break; @@ -11698,98 +11774,34 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } } #endif // TARGET_ARM - - /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */ - - if (op1->AsOp()->gtOp1->OperGet() == GT_ADDR && op1->AsOp()->gtOp2->OperGet() == GT_CNS_INT && - opts.OptimizationEnabled()) - { - // No overflow arithmetic with pointers - noway_assert(!op1->gtOverflow()); - - temp = op1->AsOp()->gtOp1->AsOp()->gtOp1; - if (!temp->OperIsLocal()) - { - temp = nullptr; - break; - } - - // Can not remove the GT_ADDR if it is currently a CSE candidate. - if (gtIsActiveCSE_Candidate(op1->AsOp()->gtOp1)) - { - break; - } - - ival1 = op1->AsOp()->gtOp2->AsIntCon()->gtIconVal; - fieldSeq = op1->AsOp()->gtOp2->AsIntCon()->gtFieldSeq; - - if (ival1 == 0 && typ == temp->TypeGet() && temp->TypeGet() != TYP_STRUCT) - { - noway_assert(!varTypeIsGC(temp->TypeGet())); - foldAndReturnTemp = true; - } - else - { - // The emitter can't handle large offsets - if (ival1 != (unsigned short)ival1) - { - break; - } - - // The emitter can get confused by invalid offsets - if (ival1 >= Compiler::lvaLclSize(temp->AsLclVarCommon()->GetLclNum())) - { - break; - } - } - // Now we can fold this into a GT_LCL_FLD below - // where we check (temp != nullptr) - } } } - // At this point we may have a lclVar or lclFld that might be foldable with a bit of extra massaging: - // - We may have a load of a local where the load has a different type than the local - // - We may have a load of a local plus an offset - // - // In these cases, we will change the lclVar or lclFld into a lclFld of the appropriate type and - // offset if doing so is legal. The only cases in which this transformation is illegal are if the load - // begins before the local or if the load extends beyond the end of the local (i.e. if the load is - // out-of-bounds w.r.t. the local). + // At this point we may have a lclVar or lclFld of some mismatched type. In this case, we will change + // the lclVar or lclFld into a lclFld of the appropriate type if doing so is legal. The only cases in + // which this transformation is illegal is when we have a STRUCT indirection, as we do not have the + // necessary layout information, or if the load would extend beyond the local. if ((temp != nullptr) && !foldAndReturnTemp) { - assert(temp->OperIsLocal()); + assert(temp->OperIs(GT_LCL_VAR, GT_LCL_FLD)); - unsigned lclNum = temp->AsLclVarCommon()->GetLclNum(); + unsigned lclNum = temp->AsLclVarCommon()->GetLclNum(); + unsigned lclOffs = temp->AsLclVarCommon()->GetLclOffs(); // Make sure we do not enregister this lclVar. lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField)); - // If the size of the load is greater than the size of the lclVar, we cannot fold this access into - // a lclFld: the access represented by an lclFld node must begin at or after the start of the - // lclVar and must not extend beyond the end of the lclVar. - if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= lvaLclExactSize(lclNum))) + if ((typ != TYP_STRUCT) && ((lclOffs + genTypeSize(typ)) <= lvaLclExactSize(lclNum))) { - GenTreeLclFld* lclFld; - - // We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival' - // or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival' - // Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type. + // We will change the type of the node to match the orginal GT_IND type. // - if (temp->OperGet() == GT_LCL_FLD) - { - lclFld = temp->AsLclFld(); - lclFld->SetLclOffs(lclFld->GetLclOffs() + static_cast(ival1)); - } - else // We have a GT_LCL_VAR. + temp->gtType = typ; + + if (temp->OperIs(GT_LCL_VAR)) { - assert(temp->OperGet() == GT_LCL_VAR); - temp->ChangeOper(GT_LCL_FLD); // Note that this makes the gtFieldSeq "NotAField". - lclFld = temp->AsLclFld(); - lclFld->SetLclOffs(static_cast(ival1)); + temp->ChangeOper(GT_LCL_FLD); } - temp->gtType = tree->gtType; foldAndReturnTemp = true; } } @@ -11798,7 +11810,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) { assert(temp != nullptr); assert(temp->TypeGet() == typ); - assert((op1->OperGet() == GT_ADD) || (op1->OperGet() == GT_ADDR)); + assert(op1->OperIs(GT_ADDR)); // Copy the value of GTF_DONT_CSE from the original tree to `temp`: it can be set for // 'temp' because a GT_ADDR always marks it for its operand. @@ -11806,12 +11818,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) temp->gtFlags |= (tree->gtFlags & GTF_DONT_CSE); temp->SetVNsFromNode(tree); - if (op1->OperGet() == GT_ADD) - { - DEBUG_DESTROY_NODE(op1->AsOp()->gtOp1); // GT_ADDR - DEBUG_DESTROY_NODE(op1->AsOp()->gtOp2); // GT_CNS_INT - } - DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR + DEBUG_DESTROY_NODE(op1); // GT_ADDR DEBUG_DESTROY_NODE(tree); // GT_IND // If the result of the fold is a local var, we may need to perform further adjustments e.g. for @@ -12293,6 +12300,75 @@ GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast) return cast; } +//------------------------------------------------------------------------ +// fgOptimizeCastOnAssignment: Optimizes the supplied GT_ASG tree with a GT_CAST node. +// +// Arguments: +// tree - the cast tree to optimize +// +// Return Value: +// The optimized tree (must be GT_ASG). +// +GenTree* Compiler::fgOptimizeCastOnAssignment(GenTreeOp* asg) +{ + assert(asg->OperIs(GT_ASG)); + + GenTree* const op1 = asg->gtGetOp1(); + GenTree* const op2 = asg->gtGetOp2(); + + assert(op2->OperIs(GT_CAST)); + + GenTree* const effectiveOp1 = op1->gtEffectiveVal(); + + if (!effectiveOp1->OperIs(GT_IND, GT_LCL_VAR)) + return asg; + + if (effectiveOp1->OperIs(GT_LCL_VAR) && + !lvaGetDesc(effectiveOp1->AsLclVarCommon()->GetLclNum())->lvNormalizeOnLoad()) + return asg; + + if (op2->gtOverflow()) + return asg; + + if (gtIsActiveCSE_Candidate(op2)) + return asg; + + GenTreeCast* cast = op2->AsCast(); + var_types castToType = cast->CastToType(); + var_types castFromType = cast->CastFromType(); + + if (gtIsActiveCSE_Candidate(cast->CastOp())) + return asg; + + if (!varTypeIsSmall(effectiveOp1)) + return asg; + + if (!varTypeIsSmall(castToType)) + return asg; + + if (!varTypeIsIntegral(castFromType)) + return asg; + + // If we are performing a narrowing cast and + // castToType is larger or the same as op1's type + // then we can discard the cast. + if (genTypeSize(castToType) < genTypeSize(effectiveOp1)) + return asg; + + if (genActualType(castFromType) == genActualType(castToType)) + { + // Removes the cast. + asg->gtOp2 = cast->CastOp(); + } + else + { + // This is a type-changing cast so we cannot remove it entirely. + cast->gtCastType = genActualType(castToType); + } + + return asg; +} + //------------------------------------------------------------------------ // fgOptimizeEqualityComparisonWithConst: optimizes various EQ/NE(OP, CONST) patterns. // @@ -12529,6 +12605,123 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) return cmp; } +//------------------------------------------------------------------------ +// fgOptimizeRelationalComparisonWithFullRangeConst: optimizes a comparison operation. +// +// Recognizes "Always false"/"Always true" comparisons against various full range constant operands and morphs +// them into zero/one. +// +// Arguments: +// cmp - the GT_LT/GT_GT tree to morph. +// +// Return Value: +// 1. The unmodified "cmp" tree. +// 2. A CNS_INT node containing zero. +// 3. A CNS_INT node containing one. +// Assumptions: +// The second operand is an integral constant or the first operand is an integral constant. +// +GenTree* Compiler::fgOptimizeRelationalComparisonWithFullRangeConst(GenTreeOp* cmp) +{ + if (gtTreeHasSideEffects(cmp, GTF_SIDE_EFFECT)) + { + return cmp; + } + + int64_t lhsMin; + int64_t lhsMax; + if (cmp->gtGetOp1()->IsIntegralConst()) + { + lhsMin = cmp->gtGetOp1()->AsIntConCommon()->IntegralValue(); + lhsMax = lhsMin; + } + else + { + IntegralRange lhsRange = IntegralRange::ForNode(cmp->gtGetOp1(), this); + lhsMin = IntegralRange::SymbolicToRealValue(lhsRange.GetLowerBound()); + lhsMax = IntegralRange::SymbolicToRealValue(lhsRange.GetUpperBound()); + } + + int64_t rhsMin; + int64_t rhsMax; + if (cmp->gtGetOp2()->IsIntegralConst()) + { + rhsMin = cmp->gtGetOp2()->AsIntConCommon()->IntegralValue(); + rhsMax = rhsMin; + } + else + { + IntegralRange rhsRange = IntegralRange::ForNode(cmp->gtGetOp2(), this); + rhsMin = IntegralRange::SymbolicToRealValue(rhsRange.GetLowerBound()); + rhsMax = IntegralRange::SymbolicToRealValue(rhsRange.GetUpperBound()); + } + + genTreeOps op = cmp->gtOper; + if ((op != GT_LT) && (op != GT_LE)) + { + op = GenTree::SwapRelop(op); + std::swap(lhsMin, rhsMin); + std::swap(lhsMax, rhsMax); + } + + GenTree* ret = nullptr; + + if (cmp->IsUnsigned()) + { + if ((lhsMin < 0) && (lhsMax >= 0)) + { + // [0, (uint64_t)lhsMax] U [(uint64_t)lhsMin, MaxValue] + lhsMin = 0; + lhsMax = -1; + } + + if ((rhsMin < 0) && (rhsMax >= 0)) + { + // [0, (uint64_t)rhsMax] U [(uint64_t)rhsMin, MaxValue] + rhsMin = 0; + rhsMax = -1; + } + + if (((op == GT_LT) && ((uint64_t)lhsMax < (uint64_t)rhsMin)) || + ((op == GT_LE) && ((uint64_t)lhsMax <= (uint64_t)rhsMin))) + { + ret = gtNewOneConNode(TYP_INT); + } + else if (((op == GT_LT) && ((uint64_t)lhsMin >= (uint64_t)rhsMax)) || + ((op == GT_LE) && ((uint64_t)lhsMin > (uint64_t)rhsMax))) + { + ret = gtNewZeroConNode(TYP_INT); + } + } + else + { + // [x0, x1] < [y0, y1] is false if x0 >= y1 + // [x0, x1] <= [y0, y1] is false if x0 > y1 + if (((op == GT_LT) && (lhsMin >= rhsMax)) || (((op == GT_LE) && (lhsMin > rhsMax)))) + { + ret = gtNewZeroConNode(TYP_INT); + } + // [x0, x1] < [y0, y1] is true if x1 < y0 + else if ((op == GT_LT) && (lhsMax < rhsMin)) + { + ret = gtNewOneConNode(TYP_INT); + } + } + + if (ret != nullptr) + { + fgUpdateConstTreeValueNumber(ret); + + DEBUG_DESTROY_NODE(cmp); + + INDEBUG(ret->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + + return ret; + } + + return cmp; +} + //------------------------------------------------------------------------ // fgOptimizeRelationalComparisonWithConst: optimizes a comparison operation. // @@ -12813,9 +13006,39 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) return op1; } - // Note that these transformations are legal for floating-point ADDs as well. if (opts.OptimizationEnabled()) { + // Reduce local addresses: "ADD(ADDR(LCL_VAR), OFFSET)" => "ADDR(LCL_FLD OFFSET)". + // TODO-ADDR: do "ADD(LCL_FLD/VAR_ADDR, OFFSET)" => "LCL_FLD_ADDR" instead. + // + if (op1->OperIs(GT_ADDR) && op2->IsCnsIntOrI() && op1->gtGetOp1()->OperIsLocalRead()) + { + GenTreeUnOp* addrNode = op1->AsUnOp(); + GenTreeLclVarCommon* lclNode = addrNode->gtGetOp1()->AsLclVarCommon(); + GenTreeIntCon* offsetNode = op2->AsIntCon(); + if (FitsIn(offsetNode->IconValue())) + { + unsigned offset = lclNode->GetLclOffs() + static_cast(offsetNode->IconValue()); + + // Note: the emitter does not expect out-of-bounds access for LCL_FLD_ADDR. + if (FitsIn(offset) && (offset < lvaLclExactSize(lclNode->GetLclNum()))) + { + // Types of location nodes under ADDRs do not matter. We arbitrarily choose TYP_UBYTE. + lclNode->ChangeType(TYP_UBYTE); + lclNode->SetOper(GT_LCL_FLD); + lclNode->AsLclFld()->SetLclOffs(offset); + lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField)); + + addrNode->SetVNsFromNode(add); + + DEBUG_DESTROY_NODE(offsetNode); + DEBUG_DESTROY_NODE(add); + + return addrNode; + } + } + } + // - a + b = > b - a // ADD((NEG(a), b) => SUB(b, a) @@ -12910,6 +13133,20 @@ GenTree* Compiler::fgOptimizeMultiply(GenTreeOp* mul) if (op2->IsIntegralConst()) { + // We should not get here for 64-bit multiplications on 32-bit. + assert(op2->IsCnsIntOrI()); + + // MUL(NEG(a), C) => MUL(a, NEG(C)) + if (opts.OptimizationEnabled() && op1->OperIs(GT_NEG) && !op2->IsIconHandle()) + { + mul->gtOp1 = op1->AsUnOp()->gtGetOp1(); + op2->AsIntCon()->gtIconVal = -op2->AsIntCon()->gtIconVal; + fgUpdateConstTreeValueNumber(op2); + DEBUG_DESTROY_NODE(op1); + + op1 = mul->gtOp1; + } + ssize_t mult = op2->AsIntConCommon()->IconValue(); if (mult == 0) @@ -13286,41 +13523,19 @@ GenTree* Compiler::fgMorphRetInd(GenTreeUnOp* ret) if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR)) { - // If struct promotion was undone, adjust the annotations - if (fgGlobalMorph && fgMorphImplicitByRefArgs(addr)) - { - return ind; - } - // If `return` retypes LCL_VAR as a smaller struct it should not set `doNotEnregister` on that // LclVar. // Example: in `Vector128:AsVector2` we have RETURN SIMD8(OBJ SIMD8(ADDR byref(LCL_VAR SIMD16))). GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar(); + if (!lvaIsImplicitByRefLocal(lclVar->GetLclNum())) { assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(ind)); - unsigned indSize; - if (ind->OperIs(GT_IND)) - { - indSize = genTypeSize(ind); - } - else - { - indSize = ind->AsBlk()->GetLayout()->GetSize(); - } - - LclVarDsc* varDsc = lvaGetDesc(lclVar); - unsigned lclVarSize; - if (!lclVar->TypeIs(TYP_STRUCT)) + LclVarDsc* varDsc = lvaGetDesc(lclVar); + unsigned indSize = ind->Size(); + unsigned lclVarSize = lvaLclExactSize(lclVar->GetLclNum()); - { - lclVarSize = genTypeSize(varDsc->TypeGet()); - } - else - { - lclVarSize = varDsc->lvExactSize; - } // TODO: change conditions in `canFold` to `indSize <= lclVarSize`, but currently do not support `BITCAST // int<-SIMD16` etc. assert((indSize <= lclVarSize) || varDsc->lvDoNotEnregister); @@ -13355,6 +13570,7 @@ GenTree* Compiler::fgMorphRetInd(GenTreeUnOp* ret) } } } + return ind; } @@ -14258,23 +14474,6 @@ GenTree* Compiler::fgMorphTree(GenTree* tree, MorphAddrContext* mac) } #endif - if (fgGlobalMorph) - { - // Apply any rewrites for implicit byref arguments before morphing the - // tree. - - if (fgMorphImplicitByRefArgs(tree)) - { -#ifdef DEBUG - if (verbose && treesBeforeAfterMorph) - { - printf("\nfgMorphTree (%d), after implicit-byref rewrite:\n", thisMorphNum); - gtDispTree(tree); - } -#endif - } - } - /*------------------------------------------------------------------------- * fgMorphTree() can potentially replace a tree with another, and the * caller has to store the return value correctly. @@ -14924,18 +15123,16 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) noway_assert(lastStmt->GetRootNode()->gtOper == GT_SWITCH); - /* Did we fold the conditional */ + // Did we fold the conditional noway_assert(lastStmt->GetRootNode()->AsOp()->gtOp1); - GenTree* condTree; - condTree = lastStmt->GetRootNode()->AsOp()->gtOp1; - GenTree* cond; - cond = condTree->gtEffectiveVal(true); + GenTree* condTree = lastStmt->GetRootNode()->AsOp()->gtOp1; + GenTree* cond = condTree->gtEffectiveVal(true); if (cond->OperIsConst()) { - /* Yupee - we folded the conditional! - * Remove the conditional statement */ + // Yupee - we folded the conditional! + // Remove the conditional statement noway_assert(cond->gtOper == GT_CNS_INT); @@ -14953,17 +15150,13 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) result = FoldResult::FOLD_REMOVED_LAST_STMT; } - /* modify the flow graph */ + // modify the flow graph - /* Find the actual jump target */ - unsigned switchVal; - switchVal = (unsigned)cond->AsIntCon()->gtIconVal; - unsigned jumpCnt; - jumpCnt = block->bbJumpSwt->bbsCount; - BasicBlock** jumpTab; - jumpTab = block->bbJumpSwt->bbsDstTab; - bool foundVal; - foundVal = false; + // Find the actual jump target + size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal; + unsigned jumpCnt = block->bbJumpSwt->bbsCount; + BasicBlock** jumpTab = block->bbJumpSwt->bbsDstTab; + bool foundVal = false; for (unsigned val = 0; val < jumpCnt; val++, jumpTab++) { @@ -14978,20 +15171,20 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block) { if (curJump != block->bbNext) { - /* transform the basic block into a BBJ_ALWAYS */ + // transform the basic block into a BBJ_ALWAYS block->bbJumpKind = BBJ_ALWAYS; block->bbJumpDest = curJump; } else { - /* transform the basic block into a BBJ_NONE */ + // transform the basic block into a BBJ_NONE block->bbJumpKind = BBJ_NONE; } foundVal = true; } else { - /* Remove 'block' from the predecessor list of 'curJump' */ + // Remove 'block' from the predecessor list of 'curJump' fgRemoveRefPred(curJump, block); } } @@ -16702,7 +16895,7 @@ void Compiler::fgMorphLocalField(GenTree* tree, GenTree* parent) void Compiler::fgResetImplicitByRefRefCount() { -#if (defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS #ifdef DEBUG if (verbose) { @@ -16725,7 +16918,7 @@ void Compiler::fgResetImplicitByRefRefCount() } } -#endif // (TARGET_AMD64 && !UNIX_AMD64_ABI) || TARGET_ARM64 || TARGET_LOONGARCH64 +#endif // FEATURE_IMPLICIT_BYREFS } //------------------------------------------------------------------------ @@ -16734,12 +16927,12 @@ void Compiler::fgResetImplicitByRefRefCount() // which struct promotions of implicit byrefs to keep or discard. // For those which are kept, insert the appropriate initialization code. // For those which are to be discarded, annotate the promoted field locals -// so that fgMorphImplicitByRefArgs will know to rewrite their appearances -// using indirections off the pointer parameters. - +// so that fgMorphExpandImplicitByRefArg will know to rewrite their +// appearances using indirections off the pointer parameters. +// void Compiler::fgRetypeImplicitByRefArgs() { -#if (defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS #ifdef DEBUG if (verbose) { @@ -16860,7 +17053,7 @@ void Compiler::fgRetypeImplicitByRefArgs() if (undoPromotion) { - // Leave lvParentLcl pointing to the parameter so that fgMorphImplicitByRefArgs + // Leave lvParentLcl pointing to the parameter so that fgMorphExpandImplicitByRefArg // will know to rewrite appearances of this local. assert(fieldVarDsc->lvParentLcl == lclNum); } @@ -16897,7 +17090,7 @@ void Compiler::fgRetypeImplicitByRefArgs() // have these fields. varDsc->lvFieldCnt = 0; - // Hijack lvPromoted to communicate to fgMorphImplicitByRefArgs + // Hijack lvPromoted to communicate to fgMorphExpandImplicitByRefArg // whether references to the struct should be rewritten as // indirections off the pointer (not promoted) or references // to the new struct local (promoted). @@ -16909,10 +17102,10 @@ void Compiler::fgRetypeImplicitByRefArgs() // promotion wanted to promote but that aren't considered profitable to // rewrite. It hijacks lvFieldLclStart to communicate to // fgMarkDemotedImplicitByRefArgs that it needs to clean up annotations left - // on such args for fgMorphImplicitByRefArgs to consult in the interim. + // on such args for fgMorphExpandImplicitByRefArg to consult in the interim. // Here we have an arg that was simply never promoted, so make sure it doesn't - // have nonzero lvFieldLclStart, since that would confuse fgMorphImplicitByRefArgs - // and fgMarkDemotedImplicitByRefArgs. + // have nonzero lvFieldLclStart, since that would confuse the aforementioned + // functions. assert(varDsc->lvFieldLclStart == 0); } @@ -16945,20 +17138,21 @@ void Compiler::fgRetypeImplicitByRefArgs() } } -#endif // (TARGET_AMD64 && !UNIX_AMD64_ABI) || TARGET_ARM64 || TARGET_LOONGARCH64 +#endif // FEATURE_IMPLICIT_BYREFS } //------------------------------------------------------------------------ // fgMarkDemotedImplicitByRefArgs: Clear annotations for any implicit byrefs that struct promotion // asked to promote. Appearances of these have now been rewritten -// (by fgMorphImplicitByRefArgs) using indirections from the pointer -// parameter or references to the promotion temp, as appropriate. - +// (by fgMorphExpandImplicitByRefArg) using indirections from +// the pointer parameter or references to the promotion temp, as +// appropriate. +// void Compiler::fgMarkDemotedImplicitByRefArgs() { JITDUMP("\n*************** In fgMarkDemotedImplicitByRefArgs()\n"); -#if (defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS for (unsigned lclNum = 0; lclNum < info.compArgsCount; lclNum++) { @@ -16970,13 +17164,13 @@ void Compiler::fgMarkDemotedImplicitByRefArgs() if (varDsc->lvPromoted) { - // The parameter is simply a pointer now, so clear lvPromoted. It was left set - // by fgRetypeImplicitByRefArgs to communicate to fgMorphImplicitByRefArgs that + // The parameter is simply a pointer now, so clear lvPromoted. It was left set by + // fgRetypeImplicitByRefArgs to communicate to fgMorphExpandImplicitByRefArg that // appearances of this arg needed to be rewritten to a new promoted struct local. varDsc->lvPromoted = false; // Clear the lvFieldLclStart value that was set by fgRetypeImplicitByRefArgs - // to tell fgMorphImplicitByRefArgs which local is the new promoted struct one. + // to tell fgMorphExpandImplicitByRefArg which local is the new promoted struct one. varDsc->lvFieldLclStart = 0; } else if (varDsc->lvFieldLclStart != 0) @@ -17019,181 +17213,7 @@ void Compiler::fgMarkDemotedImplicitByRefArgs() } } -#endif // (TARGET_AMD64 && !UNIX_AMD64_ABI) || TARGET_ARM64 || TARGET_LOONGARCH64 -} - -/***************************************************************************** - * - * Morph irregular parameters - * for x64 and ARM64 this means turning them into byrefs, adding extra indirs. - */ -bool Compiler::fgMorphImplicitByRefArgs(GenTree* tree) -{ -#if (!defined(TARGET_AMD64) || defined(UNIX_AMD64_ABI)) && !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) - - return false; - -#else // (TARGET_AMD64 && !UNIX_AMD64_ABI) || TARGET_ARM64 || TARGET_LOONGARCH64 - - bool changed = false; - - // Implicit byref morphing needs to know if the reference to the parameter is a - // child of GT_ADDR or not, so this method looks one level down and does the - // rewrite whenever a child is a reference to an implicit byref parameter. - if (tree->gtOper == GT_ADDR) - { - if (tree->AsOp()->gtOp1->gtOper == GT_LCL_VAR) - { - GenTree* morphedTree = fgMorphImplicitByRefArgs(tree, true); - changed = (morphedTree != nullptr); - assert(!changed || (morphedTree == tree)); - } - } - else - { - for (GenTree** pTree : tree->UseEdges()) - { - GenTree** pTreeCopy = pTree; - GenTree* childTree = *pTree; - if (childTree->gtOper == GT_LCL_VAR) - { - GenTree* newChildTree = fgMorphImplicitByRefArgs(childTree, false); - if (newChildTree != nullptr) - { - changed = true; - *pTreeCopy = newChildTree; - } - } - } - } - - return changed; -#endif // (TARGET_AMD64 && !UNIX_AMD64_ABI) || TARGET_ARM64 || TARGET_LOONGARCH64 -} - -GenTree* Compiler::fgMorphImplicitByRefArgs(GenTree* tree, bool isAddr) -{ - assert((tree->gtOper == GT_LCL_VAR) || ((tree->gtOper == GT_ADDR) && (tree->AsOp()->gtOp1->gtOper == GT_LCL_VAR))); - assert(isAddr == (tree->gtOper == GT_ADDR)); - - GenTree* lclVarTree = isAddr ? tree->AsOp()->gtOp1 : tree; - unsigned lclNum = lclVarTree->AsLclVarCommon()->GetLclNum(); - LclVarDsc* lclVarDsc = lvaGetDesc(lclNum); - - CORINFO_FIELD_HANDLE fieldHnd; - unsigned fieldOffset = 0; - var_types fieldRefType = TYP_UNKNOWN; - - if (lvaIsImplicitByRefLocal(lclNum)) - { - // The SIMD transformation to coalesce contiguous references to SIMD vector fields will - // re-invoke the traversal to mark address-taken locals. - // So, we may encounter a tree that has already been transformed to TYP_BYREF. - // If we do, leave it as-is. - if (!varTypeIsStruct(lclVarTree)) - { - assert(lclVarTree->TypeGet() == TYP_BYREF); - - return nullptr; - } - else if (lclVarDsc->lvPromoted) - { - // fgRetypeImplicitByRefArgs created a new promoted struct local to represent this - // arg. Rewrite this to refer to the new local. - assert(lclVarDsc->lvFieldLclStart != 0); - lclVarTree->AsLclVarCommon()->SetLclNum(lclVarDsc->lvFieldLclStart); - return tree; - } - - fieldHnd = nullptr; - } - else if (lclVarDsc->lvIsStructField && lvaIsImplicitByRefLocal(lclVarDsc->lvParentLcl)) - { - // This was a field reference to an implicit-by-reference struct parameter that was - // dependently promoted; update it to a field reference off the pointer. - // Grab the field handle from the struct field lclVar. - fieldHnd = lclVarDsc->lvFieldHnd; - fieldOffset = lclVarDsc->lvFldOffset; - assert(fieldHnd != nullptr); - // Update lclNum/lclVarDsc to refer to the parameter - lclNum = lclVarDsc->lvParentLcl; - lclVarDsc = lvaGetDesc(lclNum); - fieldRefType = lclVarTree->TypeGet(); - } - else - { - // We only need to tranform the 'marked' implicit by ref parameters - return nullptr; - } - - // This is no longer a def of the lclVar, even if it WAS a def of the struct. - lclVarTree->gtFlags &= ~(GTF_LIVENESS_MASK); - - if (isAddr) - { - if (fieldHnd == nullptr) - { - // change &X into just plain X - tree->ReplaceWith(lclVarTree, this); - tree->gtType = TYP_BYREF; - } - else - { - // change &(X.f) [i.e. GT_ADDR of local for promoted arg field] - // into &(X, f) [i.e. GT_ADDR of GT_FIELD off ptr param] - lclVarTree->AsLclVarCommon()->SetLclNum(lclNum); - lclVarTree->gtType = TYP_BYREF; - tree->AsOp()->gtOp1 = gtNewFieldRef(fieldRefType, fieldHnd, lclVarTree, fieldOffset); - } - -#ifdef DEBUG - if (verbose) - { - printf("Replacing address of implicit by ref struct parameter with byref:\n"); - } -#endif // DEBUG - } - else - { - // Change X into OBJ(X) or FIELD(X, f) - var_types structType = tree->gtType; - tree->gtType = TYP_BYREF; - - if (fieldHnd) - { - tree->AsLclVarCommon()->SetLclNum(lclNum); - tree = gtNewFieldRef(fieldRefType, fieldHnd, tree, fieldOffset); - } - else - { - tree = gtNewObjNode(lclVarDsc->GetStructHnd(), tree); - - if (structType == TYP_STRUCT) - { - gtSetObjGcInfo(tree->AsObj()); - } - } - - // TODO-CQ: If the VM ever stops violating the ABI and passing heap references - // we could apply TGT_NOT_HEAP here. - tree->gtFlags = (tree->gtFlags & GTF_COMMON_MASK); - -#ifdef DEBUG - if (verbose) - { - printf("Replacing value of implicit by ref struct parameter with indir of parameter:\n"); - } -#endif // DEBUG - } - -#ifdef DEBUG - if (verbose) - { - gtDispTree(tree); - } -#endif // DEBUG - - return tree; +#endif // FEATURE_IMPLICIT_BYREFS } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index af04a6b11fcc3..7b6347e9628ee 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -385,13 +385,13 @@ unsigned Compiler::optValnumCSE_Index(GenTree* tree, Statement* stmt) bool isSharedConst = false; int configValue = JitConfig.JitConstCSE(); -#if defined(TARGET_ARM64) - // ARM64 - allow to combine with nearby offsets, when config is not 2 or 4 - if ((configValue != CONST_CSE_ENABLE_ARM64_NO_SHARING) && (configValue != CONST_CSE_ENABLE_ALL_NO_SHARING)) +#if defined(TARGET_ARMARCH) + // ARMARCH - allow to combine with nearby offsets, when config is not 2 or 4 + if ((configValue != CONST_CSE_ENABLE_ARM_NO_SHARING) && (configValue != CONST_CSE_ENABLE_ALL_NO_SHARING)) { enableSharedConstCSE = true; } -#endif // TARGET_ARM64 +#endif // TARGET_ARMARCH // All Platforms - also allow to combine with nearby offsets, when config is 3 if (configValue == CONST_CSE_ENABLE_ALL) @@ -785,10 +785,12 @@ bool Compiler::optValnumCSE_Locate() } // Don't allow CSE of constants if it is disabled - // if (tree->IsIntegralConst()) { - if (!enableConstCSE) + if (!enableConstCSE && + // Unconditionally allow these constant handles to be CSE'd + !tree->IsIconHandle(GTF_ICON_STATIC_HDL) && !tree->IsIconHandle(GTF_ICON_CLASS_HDL) && + !tree->IsIconHandle(GTF_ICON_STR_HDL)) { continue; } @@ -2960,9 +2962,9 @@ class CSE_Heuristic do { /* Process the next node in the list */ - GenTree* exp = lst->tslTree; - Statement* stmt = lst->tslStmt; - BasicBlock* blk = lst->tslBlock; + GenTree* const exp = lst->tslTree; + Statement* const stmt = lst->tslStmt; + BasicBlock* const blk = lst->tslBlock; /* Advance to the next node in the list */ lst = lst->tslNext; @@ -3210,9 +3212,9 @@ class CSE_Heuristic noway_assert(asg->AsOp()->gtOp2 == val); } - // assign the proper Value Numbers - asg->gtVNPair.SetBoth(ValueNumStore::VNForVoid()); // The GT_ASG node itself is $VN.Void - asg->AsOp()->gtOp1->gtVNPair = val->gtVNPair; // The dest op is the same as 'val' + // Assign the proper Value Numbers. + asg->gtVNPair = ValueNumStore::VNPForVoid(); // The GT_ASG node itself is $VN.Void. + asg->AsOp()->gtOp1->gtVNPair = ValueNumStore::VNPForVoid(); // As is the LHS. noway_assert(asg->AsOp()->gtOp1->gtOper == GT_LCL_VAR); @@ -3261,7 +3263,7 @@ class CSE_Heuristic cseUse->SetDoNotCSE(); } } - cseUse->gtVNPair = val->gtVNPair; // The 'cseUse' is equal to 'val' + cseUse->gtVNPair = exp->gtVNPair; // The 'cseUse' is equal to the original expression. /* Create a comma node for the CSE assignment */ cse = m_pCompiler->gtNewOperNode(GT_COMMA, expTyp, origAsg, cseUse); @@ -3582,7 +3584,6 @@ bool Compiler::optIsCSEcandidate(GenTree* tree) case GT_ARR_ELEM: case GT_ARR_LENGTH: - case GT_LCL_FLD: return true; case GT_LCL_VAR: @@ -3685,7 +3686,9 @@ bool Compiler::optIsCSEcandidate(GenTree* tree) return true; // allow Intrinsics to be CSE-ed case GT_OBJ: - return varTypeIsEnregisterable(type); // Allow enregisterable GT_OBJ's to be CSE-ed. (i.e. SIMD types) + case GT_LCL_FLD: + // TODO-1stClassStructs: support CSE for enregisterable TYP_STRUCTs. + return varTypeIsEnregisterable(type); case GT_COMMA: return true; // Allow GT_COMMA nodes to be CSE-ed. diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index b848d6400bca8..315b19caf7ddf 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -1725,9 +1725,13 @@ class LoopSearch // Thus, we have to be very careful and after entry discovery check that it is indeed // the only place we enter the loop (especially for non-reducible flow graphs). + JITDUMP("FindLoop: checking head:" FMT_BB " top:" FMT_BB " bottom:" FMT_BB "\n", head->bbNum, top->bbNum, + bottom->bbNum); + if (top->bbNum > bottom->bbNum) // is this a backward edge? (from BOTTOM to TOP) { // Edge from BOTTOM to TOP is not a backward edge + JITDUMP(" " FMT_BB "->" FMT_BB " is not a backedge\n", bottom->bbNum, top->bbNum); return false; } @@ -1735,11 +1739,13 @@ class LoopSearch { // Not a true back-edge; bottom is a block added to reconnect fall-through during // loop processing, so its block number does not reflect its position. + JITDUMP(" " FMT_BB "->" FMT_BB " is not a true backedge\n", bottom->bbNum, top->bbNum); return false; } if (bottom->KindIs(BBJ_EHFINALLYRET, BBJ_EHFILTERRET, BBJ_EHCATCHRET, BBJ_CALLFINALLY, BBJ_SWITCH)) { + JITDUMP(" bottom odd jump kind\n"); // 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. return false; @@ -1759,6 +1765,7 @@ class LoopSearch if (entry == nullptr) { // For now, we only recognize loops where HEAD has some successor ENTRY in the loop. + JITDUMP(" can't find entry\n"); return false; } @@ -1773,12 +1780,14 @@ class LoopSearch if (!HasSingleEntryCycle()) { // There isn't actually a loop between TOP and BOTTOM + JITDUMP(" not single entry cycle\n"); return false; } if (!loopBlocks.IsMember(top->bbNum)) { // The "back-edge" we identified isn't actually part of the flow cycle containing ENTRY + JITDUMP(" top not in loop\n"); return false; } @@ -1828,6 +1837,7 @@ class LoopSearch if (!MakeCompactAndFindExits()) { // Unable to preserve well-formed loop during compaction. + JITDUMP(" can't compact\n"); return false; } @@ -1928,6 +1938,7 @@ class LoopSearch } else if (!comp->fgDominate(entry, block)) { + JITDUMP(" (find cycle) entry:" FMT_BB " does not dominate " FMT_BB "\n", entry->bbNum, block->bbNum); return false; } @@ -1960,6 +1971,8 @@ class LoopSearch } // There are multiple entries to this loop, don't consider it. + + JITDUMP(" (find cycle) multiple entry:" FMT_BB "\n", block->bbNum); return false; } @@ -1967,6 +1980,7 @@ class LoopSearch if (predBlock == entry) { // We have indeed found a cycle in the flow graph. + JITDUMP(" (find cycle) found cycle\n"); isFirstVisit = !foundCycle; foundCycle = true; assert(loopBlocks.IsMember(predBlock->bbNum)); @@ -2664,6 +2678,9 @@ void Compiler::optFindNaturalLoops() // Make sure that loops are canonical: that every loop has a unique "top", by creating an empty "nop" // one, if necessary, for loops containing others that share a "top." + // + // Also make sure that no loop's "bottom" is another loop's "head". + // for (unsigned char loopInd = 0; loopInd < optLoopCount; loopInd++) { // Traverse the outermost loops as entries into the loop nest; so skip non-outermost. @@ -2874,49 +2891,229 @@ bool Compiler::optIsLoopEntry(BasicBlock* block) const return false; } -// Canonicalize the loop nest rooted at parent loop 'loopInd'. -// Returns 'true' if the flow graph is modified. +//----------------------------------------------------------------------------- +// optCanonicalizeLoopNest: Canonicalize a loop nest +// +// Arguments: +// loopInd - index of outermost loop in the nest +// +// Returns: +// true if the flow graph was modified +// +// Notes: +// For loopInd and all contained loops, ensures each loop top's back edges +// only come from this loop. +// +// Will split top blocks and redirect edges if needed. +// bool Compiler::optCanonicalizeLoopNest(unsigned char loopInd) { - bool modified = false; - - // Is the top of the current loop in any nested loop? - if (optLoopTable[loopInd].lpTop->bbNatLoopNum != loopInd) - { - if (optCanonicalizeLoop(loopInd)) - { - modified = true; - } - } + // First canonicalize the loop. + // + bool modified = optCanonicalizeLoop(loopInd); + // Then any children. + // for (unsigned char child = optLoopTable[loopInd].lpChild; // child != BasicBlock::NOT_IN_LOOP; // child = optLoopTable[child].lpSibling) { - if (optCanonicalizeLoopNest(child)) - { - modified = true; - } + modified |= optCanonicalizeLoopNest(child); } return modified; } +//----------------------------------------------------------------------------- +// optCanonicalizeLoop: ensure that each loop top's back edges come only from +// blocks in the same loop, and that no loop head/bottom blocks coincide. +// +// Arguments: +// loopInd - index of the loop to consider +// +// Returns: +// true if flow changes were made +// +// Notes: +// +// Back edges incident on loop top fall into one three groups: +// +// (1) Outer non-loop backedges (preds dominated by entry where pred is not in loop) +// (2) The canonical backedge (pred == bottom) +// (3) Nested loop backedges or nested non-loop backedges +// (preds dominated by entry, where pred is in loop, pred != bottom) +// +// We assume dominance has already been established by loop recognition (that is, +// anything classified as a loop will have all backedges dominated by loop entry, +// so the only possible non-backedge predecessor of top will be head). +// +// We cannot check dominance here as the flow graph is being modified. +// +// If either set (1) or (3) is non-empty the loop is not canonical. +// +// This method will split the loop top into two or three blocks depending on +// whether (1) or (3) is non-empty, and redirect the edges accordingly. +// +// Loops are canoncalized outer to inner, so inner loops should never see outer loop +// non-backedges, as the parent loop canonicalization should have handled them. +// bool Compiler::optCanonicalizeLoop(unsigned char loopInd) { - // Is the top uniquely part of the current loop? - BasicBlock* t = optLoopTable[loopInd].lpTop; + bool modified = false; + BasicBlock* const b = optLoopTable[loopInd].lpBottom; + BasicBlock* const t = optLoopTable[loopInd].lpTop; + BasicBlock* const h = optLoopTable[loopInd].lpHead; + BasicBlock* const e = optLoopTable[loopInd].lpEntry; + + // Look for case (1) + // + bool doOuterCanon = false; + + for (BasicBlock* const topPredBlock : t->PredBlocks()) + { + const bool predIsInLoop = (t->bbNum <= topPredBlock->bbNum) && (topPredBlock->bbNum <= b->bbNum); + if (predIsInLoop || (topPredBlock == h)) + { + // no action needed + } + else + { + JITDUMP("in optCanonicalizeLoop: " FMT_LP " top " FMT_BB " (entry " FMT_BB " bottom " FMT_BB + ") %shas a non-loop backedge from " FMT_BB "%s\n", + loopInd, t->bbNum, e->bbNum, b->bbNum, doOuterCanon ? "also " : "", topPredBlock->bbNum, + doOuterCanon ? "" : ": need to canonicalize non-loop backedges"); + doOuterCanon = true; + } + } - if (t->bbNatLoopNum == loopInd) + if (doOuterCanon) { + const bool didCanon = optCanonicalizeLoopCore(loopInd, LoopCanonicalizationOption::Outer); + assert(didCanon); + modified |= didCanon; + } + + // Look for case (3) + // + // Outer canon should not update loop top. + // + assert(t == optLoopTable[loopInd].lpTop); + if (t->bbNatLoopNum != loopInd) + { + JITDUMP("in optCanonicalizeLoop: " FMT_LP " has top " FMT_BB " (entry " FMT_BB " bottom " FMT_BB + ") with natural loop number " FMT_LP ": need to canonicalize nested inner loop backedges\n", + loopInd, t->bbNum, e->bbNum, b->bbNum, t->bbNatLoopNum); + + const bool didCanon = optCanonicalizeLoopCore(loopInd, LoopCanonicalizationOption::Current); + assert(didCanon); + modified |= didCanon; + } + + // Check if this loopInd head is also the bottom of some sibling. + // If so, add a block in between to serve as the new head. + // + auto repairLoop = [this](unsigned char loopInd, unsigned char sibling) { + + BasicBlock* const h = optLoopTable[loopInd].lpHead; + BasicBlock* const siblingB = optLoopTable[sibling].lpBottom; + + if (h == siblingB) + { + // We have + // + // sibling.B (== loopInd.H) -e-> loopInd.T + // + // where e is a "critical edge", that is + // * sibling.B has other successors (notably sibling.T), + // * loopInd.T has other predecessors (notably loopInd.B) + // + // turn this into + // + // sibling.B -> newH (== loopInd.H) -> loopInd.T + // + // Ideally we'd just call fgSplitEdge, but we are + // not keeping pred lists in good shape. + // + BasicBlock* const t = optLoopTable[loopInd].lpTop; + assert(siblingB->bbJumpKind == BBJ_COND); + assert(siblingB->bbNext == t); + + JITDUMP(FMT_LP " head " FMT_BB " is also " FMT_LP " bottom\n", loopInd, h->bbNum, sibling); + + BasicBlock* const newH = fgNewBBbefore(BBJ_NONE, t, /*extendRegion*/ true); + + // Anything that flows into sibling will flow here. + // So we use sibling.H as our best guess for weight. + // + newH->inheritWeight(optLoopTable[sibling].lpHead); + newH->bbNatLoopNum = optLoopTable[loopInd].lpParent; + optUpdateLoopHead(loopInd, h, newH); + + return true; + } return false; + }; + + if (optLoopTable[loopInd].lpParent == BasicBlock::NOT_IN_LOOP) + { + // check against all other top-level loops + // + for (unsigned char sibling = 0; sibling < optLoopCount; sibling++) + { + if (optLoopTable[sibling].lpParent != BasicBlock::NOT_IN_LOOP) + { + continue; + } + + modified |= repairLoop(loopInd, sibling); + } + } + else + { + // check against all other sibling loops + // + const unsigned char parentLoop = optLoopTable[loopInd].lpParent; + + for (unsigned char sibling = optLoopTable[parentLoop].lpChild; // + sibling != BasicBlock::NOT_IN_LOOP; // + sibling = optLoopTable[sibling].lpSibling) + { + if (sibling == loopInd) + { + continue; + } + + modified |= repairLoop(loopInd, sibling); + } + } + + if (modified) + { + JITDUMP("Done canonicalizing " FMT_LP "\n\n", loopInd); } - JITDUMP("in optCanonicalizeLoop: " FMT_LP " has top " FMT_BB " (bottom " FMT_BB ") with natural loop number " FMT_LP - ": need to canonicalize\n", - loopInd, t->bbNum, optLoopTable[loopInd].lpBottom->bbNum, t->bbNatLoopNum); + return modified; +} - // Otherwise, the top of this loop is also part of a nested loop. +//----------------------------------------------------------------------------- +// optCanonicalizeLoopCore: ensure that each loop top's back edges come do not +// come from outer/inner loops. +// +// Arguments: +// loopInd - index of the loop to consider +// option - which set of edges to move when canonicalizing +// +// Returns: +// true if flow changes were made +// +// Notes: +// option ::Outer retargets all backedges that do not come from loops in the block. +// option ::Current retargets the canonical backedge (from bottom) +// +bool Compiler::optCanonicalizeLoopCore(unsigned char loopInd, LoopCanonicalizationOption option) +{ + // Otherwise, the top of this loop is also part of a nested loop or has + // non-loop backedges. // // Insert a new unique top for this loop. We must be careful to put this new // block in the correct EH region. Note that t->bbPrev might be in a different @@ -2992,17 +3189,41 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd) // want to copy the EH region of the back edge, since that would create a block // outside of and disjoint with the "try" region of the back edge. However, to // simplify things, we disqualify this type of loop, so we should never see this here. - - BasicBlock* h = optLoopTable[loopInd].lpHead; - BasicBlock* b = optLoopTable[loopInd].lpBottom; + // + BasicBlock* const b = optLoopTable[loopInd].lpBottom; + BasicBlock* const t = optLoopTable[loopInd].lpTop; + BasicBlock* const h = optLoopTable[loopInd].lpHead; // The loop must be entirely contained within a single handler region. assert(BasicBlock::sameHndRegion(t, b)); + // We expect h to be already "canonical" -- that is, it falls through to t + // and is not a degenerate BBJ_COND (both branches and falls through to t) + // or a side entry to the loop. + // + // Because of this, introducing a block before t automatically gives us + // the right flow out of h. + // + assert(h->bbNext == t); + assert(h->bbFallsThrough()); + assert((h->bbJumpKind == BBJ_NONE) || (h->bbJumpKind == BBJ_COND)); + if (h->bbJumpKind == BBJ_COND) + { + BasicBlock* const hj = h->bbJumpDest; + assert((hj->bbNum < t->bbNum) || (hj->bbNum > b->bbNum)); + } + // If the bottom block is in the same "try" region, then we extend the EH // region. Otherwise, we add the new block outside the "try" region. - const bool extendRegion = BasicBlock::sameTryRegion(t, b); - BasicBlock* newT = fgNewBBbefore(BBJ_NONE, t, extendRegion); + // + const bool extendRegion = BasicBlock::sameTryRegion(t, b); + BasicBlock* const newT = fgNewBBbefore(BBJ_NONE, t, extendRegion); + + // Initially give newT the same weight as t; we will subtract from + // this for each edge that does not move from t to newT. + // + newT->inheritWeight(t); + if (!extendRegion) { // We need to set the EH region manually. Set it to be the same @@ -3010,112 +3231,154 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd) newT->copyEHRegion(b); } + // NewT will be the target for the outer/current loop's backedge(s). + // + BlockToBlockMap* const blockMap = new (getAllocator(CMK_LoopOpt)) BlockToBlockMap(getAllocator(CMK_LoopOpt)); + blockMap->Set(t, newT); + // The new block can reach the same set of blocks as the old one, but don't try to reflect // that in its reachability set here -- creating the new block may have changed the BlockSet // representation from short to long, and canonicalizing loops is immediately followed by // a call to fgUpdateChangedFlowGraph which will recompute the reachability sets anyway. - // Redirect the "bottom" of the current loop to "newT". - BlockToBlockMap* blockMap = new (getAllocator(CMK_LoopOpt)) BlockToBlockMap(getAllocator(CMK_LoopOpt)); - blockMap->Set(t, newT); - optRedirectBlock(b, blockMap); - - // Redirect non-loop preds of "t" to also go to "newT". Inner loops that also branch to "t" should continue - // to do so. However, there maybe be other predecessors from outside the loop nest that need to be updated - // to point to "newT". This normally wouldn't happen, since they too would be part of the loop nest. However, - // they might have been prevented from participating in the loop nest due to different EH nesting, or some - // other reason. - // - // Note that optRedirectBlock doesn't update the predecessors list. So, if the same 't' block is processed - // multiple times while canonicalizing multiple loop nests, we'll attempt to redirect a predecessor multiple times. - // This is ok, because after the first redirection, the topPredBlock branch target will no longer match the source - // edge of the blockMap, so nothing will happen. bool firstPred = true; for (BasicBlock* const topPredBlock : t->PredBlocks()) { - // Skip if topPredBlock is in the loop. - // Note that this uses block number to detect membership in the loop. We are adding blocks during - // canonicalization, and those block numbers will be new, and larger than previous blocks. However, we work - // outside-in, so we shouldn't encounter the new blocks at the loop boundaries, or in the predecessor lists. - if (t->bbNum <= topPredBlock->bbNum && topPredBlock->bbNum <= b->bbNum) + // We set profile weight of newT assuming all edges would + // be redirected there. So, if we don't redirect this edge, + // this is how much we'll have to adjust newT's weight. + // + weight_t weightAdjust = BB_ZERO_WEIGHT; + + if (option == LoopCanonicalizationOption::Current) { - JITDUMP("in optCanonicalizeLoop: 'top' predecessor " FMT_BB " is in the range of " FMT_LP " (" FMT_BB - ".." FMT_BB "); not redirecting its bottom edge\n", - topPredBlock->bbNum, loopInd, t->bbNum, b->bbNum); - continue; + // Redirect the (one and only) true backedge of this loop. + // + if (topPredBlock != b) + { + if ((topPredBlock != h) && topPredBlock->hasProfileWeight()) + { + // Note this may overstate the adjustment, if topPredBlock is BBJ_COND. + // + weightAdjust = topPredBlock->bbWeight; + } + } + else + { + JITDUMP("in optCanonicalizeLoop (current): redirect bottom->top backedge " FMT_BB " -> " FMT_BB + " to " FMT_BB " -> " FMT_BB "\n", + topPredBlock->bbNum, t->bbNum, topPredBlock->bbNum, newT->bbNum); + optRedirectBlock(b, blockMap); + } } - - JITDUMP("in optCanonicalizeLoop: redirect top predecessor " FMT_BB " to " FMT_BB "\n", topPredBlock->bbNum, - newT->bbNum); - optRedirectBlock(topPredBlock, blockMap); - - // When we have profile data then the 'newT' block will inherit topPredBlock profile weight - if (topPredBlock->hasProfileWeight()) + else if (option == LoopCanonicalizationOption::Outer) { - // This corrects an issue when the topPredBlock has a profile based weight + // Redirect non-loop preds of "t" to go to "newT". Inner loops that also branch to "t" should continue + // to do so. However, there maybe be other predecessors from outside the loop nest that need to be updated + // to point to "newT". This normally wouldn't happen, since they too would be part of the loop nest. + // However, + // they might have been prevented from participating in the loop nest due to different EH nesting, or some + // other reason. + // + // Skip if topPredBlock is in the loop. + // Note that this uses block number to detect membership in the loop. We are adding blocks during + // canonicalization, and those block numbers will be new, and larger than previous blocks. However, we work + // outside-in, so we shouldn't encounter the new blocks at the loop boundaries, or in the predecessor lists. // - if (firstPred) + if ((t->bbNum <= topPredBlock->bbNum) && (topPredBlock->bbNum <= b->bbNum)) { - JITDUMP("in optCanonicalizeLoop: block " FMT_BB " will inheritWeight from " FMT_BB "\n", newT->bbNum, - topPredBlock->bbNum); - - newT->inheritWeight(topPredBlock); - firstPred = false; + if (topPredBlock->hasProfileWeight()) + { + // Note this may overstate the adjustment, if topPredBlock is BBJ_COND. + // + weightAdjust = topPredBlock->bbWeight; + } } else { - JITDUMP("in optCanonicalizeLoop: block " FMT_BB " will also contribute to the weight of " FMT_BB "\n", - newT->bbNum, topPredBlock->bbNum); + JITDUMP("in optCanonicalizeLoop (outer): redirect %s->top %sedge " FMT_BB " -> " FMT_BB " to " FMT_BB + " -> " FMT_BB "\n", + topPredBlock == h ? "head" : "nonloop", topPredBlock == h ? "" : "back", topPredBlock->bbNum, + t->bbNum, topPredBlock->bbNum, newT->bbNum); + optRedirectBlock(topPredBlock, blockMap); + } + } + else + { + unreached(); + } + + if (weightAdjust > BB_ZERO_WEIGHT) + { + JITDUMP("in optCanonicalizeLoop: removing block " FMT_BB " weight " FMT_WT " from " FMT_BB "\n", + topPredBlock->bbNum, weightAdjust, newT->bbNum); - weight_t newWeight = newT->getBBWeight(this) + topPredBlock->getBBWeight(this); - newT->setBBProfileWeight(newWeight); + if (newT->bbWeight >= weightAdjust) + { + newT->setBBProfileWeight(newT->bbWeight - weightAdjust); + } + else if (newT->bbWeight > BB_ZERO_WEIGHT) + { + newT->setBBProfileWeight(BB_ZERO_WEIGHT); } } } + assert(h->bbNext == newT); assert(newT->bbNext == t); - // If it had been a do-while loop (top == entry), update entry, as well. - BasicBlock* origE = optLoopTable[loopInd].lpEntry; - if (optLoopTable[loopInd].lpTop == origE) + // With the Option::Current we are changing which block is loop top. + // Make suitable updates. + // + if (option == LoopCanonicalizationOption::Current) { - optLoopTable[loopInd].lpEntry = newT; - } - optLoopTable[loopInd].lpTop = newT; + JITDUMP("in optCanonicalizeLoop (current): " FMT_BB " is now the top of loop " FMT_LP "\n", newT->bbNum, + loopInd); + + optLoopTable[loopInd].lpTop = newT; + newT->bbNatLoopNum = loopInd; - newT->bbNatLoopNum = loopInd; + // If loopInd was a do-while loop (top == entry), update entry, as well. + // + BasicBlock* const origE = optLoopTable[loopInd].lpEntry; + if (origE == t) + { + JITDUMP("updating entry of " FMT_LP " to " FMT_BB "\n", loopInd, newT->bbNum); + optLoopTable[loopInd].lpEntry = newT; + } - JITDUMP("in optCanonicalizeLoop: made new block " FMT_BB " [%p] the new unique top of loop %d.\n", newT->bbNum, - dspPtr(newT), loopInd); + // If any loops nested in "loopInd" have the same head and entry as "loopInd", + // it must be the case that they were do-while's (since "h" fell through to the entry). + // The new node "newT" becomes the head of such loops. + for (unsigned char childLoop = optLoopTable[loopInd].lpChild; // + childLoop != BasicBlock::NOT_IN_LOOP; // + childLoop = optLoopTable[childLoop].lpSibling) + { + if ((optLoopTable[childLoop].lpEntry == origE) && (optLoopTable[childLoop].lpHead == h) && + (newT->bbJumpKind == BBJ_NONE) && (newT->bbNext == origE)) + { + optUpdateLoopHead(childLoop, h, newT); - // Make sure the head block still goes to the entry... - if (h->bbJumpKind == BBJ_NONE && h->bbNext != optLoopTable[loopInd].lpEntry) - { - h->bbJumpKind = BBJ_ALWAYS; - h->bbJumpDest = optLoopTable[loopInd].lpEntry; + // Fix pred list here, so when we walk preds of child loop tops + // we see the right blocks. + // + fgReplacePred(optLoopTable[childLoop].lpTop, h, newT); + } + } } - else if (h->bbJumpKind == BBJ_COND && h->bbNext == newT && newT != optLoopTable[loopInd].lpEntry) + else if (option == LoopCanonicalizationOption::Outer) { - BasicBlock* h2 = fgNewBBafter(BBJ_ALWAYS, h, /*extendRegion*/ true); - optLoopTable[loopInd].lpHead = h2; - h2->bbJumpDest = optLoopTable[loopInd].lpEntry; - h2->bbStmtList = nullptr; - fgInsertStmtAtEnd(h2, fgNewStmtFromTree(gtNewOperNode(GT_NOP, TYP_VOID, nullptr))); - } + JITDUMP("in optCanonicalizeLoop (outer): " FMT_BB " is outside of loop " FMT_LP "\n", newT->bbNum, loopInd); - // If any loops nested in "loopInd" have the same head and entry as "loopInd", - // it must be the case that they were do-while's (since "h" fell through to the entry). - // The new node "newT" becomes the head of such loops. - for (unsigned char childLoop = optLoopTable[loopInd].lpChild; // - childLoop != BasicBlock::NOT_IN_LOOP; // - childLoop = optLoopTable[childLoop].lpSibling) - { - if (optLoopTable[childLoop].lpEntry == origE && optLoopTable[childLoop].lpHead == h && - newT->bbJumpKind == BBJ_NONE && newT->bbNext == origE) - { - optUpdateLoopHead(childLoop, h, newT); - } + // If we are lifting outer backeges, then newT belongs to our parent loop + // + newT->bbNatLoopNum = optLoopTable[loopInd].lpParent; + + // newT is now the header of this loop + // + optUpdateLoopHead(loopInd, h, newT); } + return true; } @@ -3151,6 +3414,22 @@ bool Compiler::optLoopContains(unsigned l1, unsigned l2) const } } +//----------------------------------------------------------------------------- +// optLoopEntry: For a given preheader of a loop, returns the lpEntry. +// +// Arguments: +// preHeader -- preheader of a loop +// +// Returns: +// Corresponding loop entry block. +// +BasicBlock* Compiler::optLoopEntry(BasicBlock* preHeader) +{ + assert((preHeader->bbFlags & BBF_LOOP_PREHEADER) != 0); + + return (preHeader->bbJumpDest == nullptr) ? preHeader->bbNext : preHeader->bbJumpDest; +} + //----------------------------------------------------------------------------- // optUpdateLoopHead: Replace the `head` block of a loop in the loop table. // Considers all child loops that might share the same head (recursively). @@ -5992,6 +6271,7 @@ void Compiler::optPerformHoistExpr(GenTree* origExpr, BasicBlock* exprBb, unsign { printf("\nHoisting a copy of "); printTreeID(origExpr); + printf(" " FMT_VN, origExpr->gtVNPair.GetLiberal()); printf(" from " FMT_BB " into PreHeader " FMT_BB " for loop " FMT_LP " <" FMT_BB ".." FMT_BB ">:\n", exprBb->bbNum, optLoopTable[lnum].lpHead->bbNum, lnum, optLoopTable[lnum].lpTop->bbNum, optLoopTable[lnum].lpBottom->bbNum); @@ -6262,46 +6542,51 @@ void Compiler::optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt) m_loopsConsidered++; #endif // LOOP_HOIST_STATS - optHoistThisLoop(lnum, hoistCtxt); - - VNSet* hoistedInCurLoop = hoistCtxt->ExtractHoistedInCurLoop(); + BasicBlockList* preHeadersOfChildLoops = nullptr; + BasicBlockList* firstPreHeader = nullptr; if (optLoopTable[lnum].lpChild != BasicBlock::NOT_IN_LOOP) { - // Add the ones hoisted in "lnum" to "hoistedInParents" for any nested loops. - // TODO-Cleanup: we should have a set abstraction for loops. - if (hoistedInCurLoop != nullptr) - { - for (VNSet::KeyIterator keys = hoistedInCurLoop->Begin(); !keys.Equal(hoistedInCurLoop->End()); ++keys) - { -#ifdef DEBUG - bool b; - assert(!hoistCtxt->m_hoistedInParentLoops.Lookup(keys.Get(), &b)); -#endif - hoistCtxt->m_hoistedInParentLoops.Set(keys.Get(), true); - } - } + BitVecTraits m_visitedTraits(fgBBNumMax * 2, this); + BitVec m_visited(BitVecOps::MakeEmpty(&m_visitedTraits)); for (unsigned child = optLoopTable[lnum].lpChild; child != BasicBlock::NOT_IN_LOOP; child = optLoopTable[child].lpSibling) { optHoistLoopNest(child, hoistCtxt); - } - // Now remove them. - // TODO-Cleanup: we should have a set abstraction for loops. - if (hoistedInCurLoop != nullptr) - { - for (VNSet::KeyIterator keys = hoistedInCurLoop->Begin(); !keys.Equal(hoistedInCurLoop->End()); ++keys) + if (optLoopTable[child].lpFlags & LPFLG_HAS_PREHEAD) { - // Note that we asserted when we added these that they hadn't been members, so removing is appropriate. - hoistCtxt->m_hoistedInParentLoops.Remove(keys.Get()); + // If any preheaders were found, add them to the tracking list + + BasicBlock* preHeaderBlock = optLoopTable[child].lpHead; + if (!BitVecOps::IsMember(&m_visitedTraits, m_visited, preHeaderBlock->bbNum)) + { + BitVecOps::AddElemD(&m_visitedTraits, m_visited, preHeaderBlock->bbNum); + JITDUMP(" PREHEADER: " FMT_BB "\n", preHeaderBlock->bbNum); + + // Here, we are arranging the blocks in reverse execution order, so when they are pushed + // on the stack that hoist these blocks further sees them in execution order. + if (firstPreHeader == nullptr) + { + preHeadersOfChildLoops = new (this, CMK_LoopHoist) BasicBlockList(preHeaderBlock, nullptr); + firstPreHeader = preHeadersOfChildLoops; + } + else + { + preHeadersOfChildLoops->next = + new (this, CMK_LoopHoist) BasicBlockList(preHeaderBlock, nullptr); + preHeadersOfChildLoops = preHeadersOfChildLoops->next; + } + } } } } + + optHoistThisLoop(lnum, hoistCtxt, firstPreHeader); } -void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt) +void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt, BasicBlockList* existingPreHeaders) { LoopDsc* pLoopDsc = &optLoopTable[lnum]; @@ -6413,24 +6698,61 @@ void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt) // or side-effect dependent things. // // We really should consider hoisting from conditionally executed blocks, if they are frequently executed - // and it is safe to evaluate the tree early. - // - // In particular if we have a loop nest, when scanning the outer loop we should consider hoisting from blocks - // in enclosed loops. However, this is likely to scale poorly, and we really should instead start - // hoisting inner to outer. + // and it is safe to evaluate the tree early // ArrayStack defExec(getAllocatorLoopHoist()); + + bool pushAllPreheaders = false; + if (pLoopDsc->lpExitCnt == 1) { assert(pLoopDsc->lpExit != nullptr); - JITDUMP(" Only considering hoisting in blocks that dominate exit block " FMT_BB "\n", pLoopDsc->lpExit->bbNum); - BasicBlock* cur = pLoopDsc->lpExit; + JITDUMP(" Considering hoisting in blocks that either dominate exit block " FMT_BB + " or preheaders of nested loops, if any:\n", + pLoopDsc->lpExit->bbNum); + // Push dominators, until we reach "entry" or exit the loop. + // Also push the preheaders that were added for the nested loops, + // if any, along the way such that in the final list, the dominating + // blocks are visited before the dominated blocks. + // + // TODO-CQ: In future, we should create preheaders upfront before building + // dominators so we don't have to do this extra work here. + BasicBlock* cur = pLoopDsc->lpExit; + BasicBlockList* preHeadersList = existingPreHeaders; + while (cur != nullptr && pLoopDsc->lpContains(cur) && cur != pLoopDsc->lpEntry) { + JITDUMP(" -- " FMT_BB " (dominate exit block)\n", cur->bbNum); defExec.Push(cur); cur = cur->bbIDom; + + if (preHeadersList != nullptr) + { + BasicBlock* preHeaderBlock = preHeadersList->block; + BasicBlock* lpEntry = optLoopEntry(preHeaderBlock); + if (cur->bbNum < lpEntry->bbNum) + { + JITDUMP(" -- " FMT_BB " (preheader of " FMT_LP ")\n", preHeaderBlock->bbNum, + lpEntry->bbNatLoopNum); + + defExec.Push(preHeaderBlock); + preHeadersList = preHeadersList->next; + } + } + } + + // Push the remaining preheaders, if any. This usually will happen if entry + // and exit blocks of lnum is same. + while (preHeadersList != nullptr) + { + BasicBlock* preHeaderBlock = preHeadersList->block; + JITDUMP(" -- " FMT_BB " (preheader of " FMT_LP ")\n", preHeaderBlock->bbNum, + optLoopEntry(preHeaderBlock)->bbNatLoopNum); + defExec.Push(preHeaderBlock); + preHeadersList = preHeadersList->next; } + // If we didn't reach the entry block, give up and *just* push the entry block. if (cur != pLoopDsc->lpEntry) { @@ -6438,17 +6760,37 @@ void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt) "block " FMT_BB "\n", pLoopDsc->lpEntry->bbNum); defExec.Reset(); + pushAllPreheaders = true; } - defExec.Push(pLoopDsc->lpEntry); } else // More than one exit { - JITDUMP(" only considering hoisting in entry block " FMT_BB "\n", pLoopDsc->lpEntry->bbNum); // We'll assume that only the entry block is definitely executed. // We could in the future do better. - defExec.Push(pLoopDsc->lpEntry); + + JITDUMP(" Considering hoisting in entry block " FMT_BB " because " FMT_LP " has more than one exit\n", + pLoopDsc->lpEntry->bbNum, lnum); + pushAllPreheaders = true; } + if (pushAllPreheaders) + { + // We will still push all the preheaders found. + BasicBlockList* preHeadersList = existingPreHeaders; + + while (preHeadersList != nullptr) + { + BasicBlock* preHeaderBlock = preHeadersList->block; + JITDUMP(" -- " FMT_BB " (preheader of " FMT_LP ")\n", preHeaderBlock->bbNum, + optLoopEntry(preHeaderBlock)->bbNatLoopNum); + defExec.Push(preHeaderBlock); + preHeadersList = preHeadersList->next; + } + } + + JITDUMP(" -- " FMT_BB " (entry block)\n", pLoopDsc->lpEntry->bbNum); + defExec.Push(pLoopDsc->lpEntry); + optHoistLoopBlocks(lnum, &defExec, hoistCtxt); } @@ -6765,6 +7107,24 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo return vnIsInvariant; } + bool IsHoistableOverExcepSibling(GenTree* node, bool siblingHasExcep) + { + JITDUMP(" [%06u]", dspTreeID(node)); + + if ((node->gtFlags & GTF_ALL_EFFECT) != 0) + { + // If the hoistable node has any side effects, make sure + // we don't hoist it past a sibling that throws any exception. + if (siblingHasExcep) + { + JITDUMP(" not hoistable: cannot move past node that throws exception.\n"); + return false; + } + } + JITDUMP(" hoistable\n"); + return true; + } + //------------------------------------------------------------------------ // IsTreeLoopMemoryInvariant: determine if the value number of tree // is dependent on the tree being executed within the current loop @@ -6868,6 +7228,7 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo fgWalkResult PostOrderVisit(GenTree** use, GenTree* user) { GenTree* tree = *use; + JITDUMP("----- PostOrderVisit for [%06u]\n", dspTreeID(tree)); if (tree->OperIsLocal()) { @@ -7174,6 +7535,15 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo // cctor dependent node is initially not hoistable and may become hoistable later, // when its parent comma node is visited. // + // TODO-CQ: Ideally, we should be hoisting all the nodes having side-effects in execution + // order as well as the ones that don't have side-effects at all. However, currently, we + // just restrict hoisting a node(s) (that are children of `comma`) if one of the siblings + // (which is executed before the given node) has side-effects (exceptions). "Descendants + // of ancestors might have side-effects and we might hoist nodes past them. This needs + // to be addressed properly. + bool visitedCurr = false; + bool isCommaTree = tree->OperIs(GT_COMMA); + bool hasExcep = false; for (int i = 0; i < m_valueStack.Height(); i++) { Value& value = m_valueStack.BottomRef(i); @@ -7182,17 +7552,32 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo { assert(value.Node() != tree); + if (IsHoistableOverExcepSibling(value.Node(), hasExcep)) + { + m_compiler->optHoistCandidate(value.Node(), m_currentBlock, m_loopNum, m_hoistContext); + } + // Don't hoist this tree again. value.m_hoistable = false; value.m_invariant = false; - - m_compiler->optHoistCandidate(value.Node(), m_currentBlock, m_loopNum, m_hoistContext); } else if (value.Node() != tree) { + if (visitedCurr && isCommaTree) + { + // If we have visited current tree, now we are visiting children. + // For GT_COMMA nodes, we want to track if any children throws and + // should not hoist further children past it. + hasExcep = (tree->gtFlags & GTF_EXCEPT) != 0; + } JITDUMP(" [%06u] not %s: %s\n", dspTreeID(value.Node()), value.m_invariant ? "invariant" : "hoistable", value.m_failReason); } + else + { + visitedCurr = true; + JITDUMP(" [%06u] not hoistable : current node\n", dspTreeID(value.Node())); + } } } @@ -7236,6 +7621,8 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo visitor.HoistBlock(block); } + + hoistContext->ResetHoistedInCurLoop(); } void Compiler::optHoistCandidate(GenTree* tree, BasicBlock* treeBb, unsigned lnum, LoopHoistContext* hoistCtxt) @@ -7249,17 +7636,12 @@ void Compiler::optHoistCandidate(GenTree* tree, BasicBlock* treeBb, unsigned lnu return; } - if (hoistCtxt->m_hoistedInParentLoops.Lookup(tree->gtVNPair.GetLiberal())) - { - JITDUMP(" ... already hoisted same VN in parent\n"); - // already hoisted in a parent loop, so don't hoist this expression. - return; - } - if (hoistCtxt->GetHoistedInCurLoop(this)->Lookup(tree->gtVNPair.GetLiberal())) { - JITDUMP(" ... already hoisted same VN in current\n"); // already hoisted this expression in the current loop, so don't hoist this expression. + + JITDUMP(" [%06u] ... already hoisted " FMT_VN " in " FMT_LP "\n ", dspTreeID(tree), + tree->gtVNPair.GetLiberal(), lnum); return; } diff --git a/src/coreclr/jit/patchpoint.cpp b/src/coreclr/jit/patchpoint.cpp index d1478c51c3123..bf7560dd431a1 100644 --- a/src/coreclr/jit/patchpoint.cpp +++ b/src/coreclr/jit/patchpoint.cpp @@ -78,7 +78,7 @@ class PatchpointTransformer // If we're instrumenting, we should not have decided to // put class probes here, as that is driven by looking at IL. // - assert((block->bbFlags & BBF_HAS_CLASS_PROFILE) == 0); + assert((block->bbFlags & BBF_HAS_HISTOGRAM_PROFILE) == 0); // Clear the partial comp flag. // diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 970e799d9b509..6b1575ab5f928 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -947,14 +947,14 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool return range; } // Generalized range computation not implemented for these operators - else if (binop->OperIs(GT_AND, GT_UMOD, GT_RSH)) + else if (binop->OperIs(GT_AND, GT_UMOD)) { return Range(Limit::keUnknown); } } // other operators are expected to be handled above. - assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH)); + assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH, GT_RSH)); Range* op1RangeCached = nullptr; Range op1Range = Limit(Limit::keUndef); @@ -1024,9 +1024,43 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool convertedOp2Range.ToString(m_pCompiler->getAllocatorDebugOnly()), r.ToString(m_pCompiler->getAllocatorDebugOnly())); } + else if (binop->OperIs(GT_RSH)) + { + r = RangeOps::ShiftRight(op1Range, op2Range); + JITDUMP("Right shift range: %s >> %s = %s\n", op1Range.ToString(m_pCompiler->getAllocatorDebugOnly()), + op2Range.ToString(m_pCompiler->getAllocatorDebugOnly()), + r.ToString(m_pCompiler->getAllocatorDebugOnly())); + } return r; } +//------------------------------------------------------------------------ +// GetRangeFromType: Compute the range from the given type +// +// Arguments: +// type - input type +// +// Return value: +// range that represents the values given type allows +// +Range RangeCheck::GetRangeFromType(var_types type) +{ + switch (type) + { + case TYP_BOOL: + case TYP_UBYTE: + return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, BYTE_MAX)); + case TYP_BYTE: + return Range(Limit(Limit::keConstant, INT8_MIN), Limit(Limit::keConstant, INT8_MAX)); + case TYP_USHORT: + return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, UINT16_MAX)); + case TYP_SHORT: + return Range(Limit(Limit::keConstant, INT16_MIN), Limit(Limit::keConstant, INT16_MAX)); + default: + return Range(Limit(Limit::keUnknown)); + } +} + // Compute the range for a local var definition. Range RangeCheck::ComputeRangeForLocalDef(BasicBlock* block, GenTreeLclVarCommon* lcl, @@ -1242,11 +1276,11 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr) { overflows = false; } - else if (expr->OperGet() == GT_IND) + else if (expr->OperIs(GT_IND)) { overflows = false; } - else if (expr->OperGet() == GT_COMMA) + else if (expr->OperIs(GT_COMMA)) { overflows = ComputeDoesOverflow(block, expr->gtEffectiveVal()); } @@ -1256,7 +1290,7 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr) overflows = DoesVarDefOverflow(expr->AsLclVarCommon()); } // Check if add overflows. - else if (expr->OperGet() == GT_ADD || expr->OperGet() == GT_MUL) + else if (expr->OperIs(GT_ADD, GT_MUL)) { overflows = DoesBinOpOverflow(block, expr->AsOp()); } @@ -1267,10 +1301,14 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr) overflows = false; } // Walk through phi arguments to check if phi arguments involve arithmetic that overflows. - else if (expr->OperGet() == GT_PHI) + else if (expr->OperIs(GT_PHI)) { overflows = DoesPhiOverflow(block, expr); } + else if (expr->OperIs(GT_CAST)) + { + overflows = ComputeDoesOverflow(block, expr->gtGetOp1()); + } GetOverflowMap()->Set(expr, overflows, OverflowMap::Overwrite); m_pSearchPath->Remove(expr); JITDUMP("[%06d] %s\n", Compiler::dspTreeID(expr), ((overflows) ? "overflows" : "does not overflow")); @@ -1357,7 +1395,7 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monIncreas range = ComputeRangeForBinOp(block, expr->AsOp(), monIncreasing DEBUGARG(indent + 1)); } // If phi, then compute the range for arguments, calling the result "dependent" when looping begins. - else if (expr->OperGet() == GT_PHI) + else if (expr->OperIs(GT_PHI)) { for (GenTreePhi::Use& use : expr->AsPhi()->Uses()) { @@ -1382,31 +1420,20 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monIncreas } else if (varTypeIsSmallInt(expr->TypeGet())) { - switch (expr->TypeGet()) - { - case TYP_UBYTE: - range = Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, 255)); - break; - case TYP_BYTE: - range = Range(Limit(Limit::keConstant, -128), Limit(Limit::keConstant, 127)); - break; - case TYP_USHORT: - range = Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, 65535)); - break; - case TYP_SHORT: - range = Range(Limit(Limit::keConstant, -32768), Limit(Limit::keConstant, 32767)); - break; - default: - range = Range(Limit(Limit::keUnknown)); - break; - } - + range = GetRangeFromType(expr->TypeGet()); JITDUMP("%s\n", range.ToString(m_pCompiler->getAllocatorDebugOnly())); } - else if (expr->OperGet() == GT_COMMA) + else if (expr->OperIs(GT_COMMA)) { range = GetRange(block, expr->gtEffectiveVal(), monIncreasing DEBUGARG(indent + 1)); } + else if (expr->OperIs(GT_CAST)) + { + GenTreeCast* castTree = expr->AsCast(); + // TODO: consider computing range for CastOp and intersect it + // with this + range = GetRangeFromType(castTree->CastToType()); + } else { // The expression is not recognized, so the result is unknown. diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index 49c5a2950a939..db1c25a09eda5 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -101,27 +101,27 @@ struct Limit assert(type == keBinOpArray); } - bool IsUndef() + bool IsUndef() const { return type == keUndef; } - bool IsDependent() + bool IsDependent() const { return type == keDependent; } - bool IsUnknown() + bool IsUnknown() const { return type == keUnknown; } - bool IsConstant() + bool IsConstant() const { return type == keConstant; } - int GetConstant() + int GetConstant() const { return cns; } - bool IsBinOpArray() + bool IsBinOpArray() const { return type == keBinOpArray; } @@ -170,6 +170,27 @@ struct Limit return false; } + bool ShiftRightConstant(int i) + { + switch (type) + { + case keDependent: + return true; + case keBinOpArray: + case keConstant: + // >> never overflows + assert((unsigned)i <= 31); + cns >>= i; + return true; + case keUndef: + case keUnknown: + // For these values of 'type', conservatively return false + break; + } + + return false; + } + bool Equals(Limit& l) { switch (type) @@ -257,34 +278,40 @@ struct Range // Helpers for operations performed on ranges struct RangeOps { - // Given a constant limit in "l1", add it to l2 and mutate "l2". - static Limit AddConstantLimit(Limit& l1, Limit& l2) + // Perform 'value' + 'cns' + static Limit AddConstantLimit(const Limit& value, const Limit& cns) { - assert(l1.IsConstant()); - Limit l = l2; - if (l.AddConstant(l1.GetConstant())) + assert(cns.IsConstant()); + Limit l = value; + if (l.AddConstant(cns.GetConstant())) { return l; } - else - { - return Limit(Limit::keUnknown); - } + return Limit(Limit::keUnknown); } - // Given a constant limit in "l1", multiply it to l2 and mutate "l2". - static Limit MultiplyConstantLimit(Limit& l1, Limit& l2) + // Perform 'value' * 'cns' + static Limit MultiplyConstantLimit(const Limit& value, const Limit& cns) { - assert(l1.IsConstant()); - Limit l = l2; - if (l.MultiplyConstant(l1.GetConstant())) + assert(cns.IsConstant()); + Limit l = value; + if (l.MultiplyConstant(cns.GetConstant())) { return l; } - else + return Limit(Limit::keUnknown); + } + + // Perform 'value' >> 'cns' + static Limit ShiftRightConstantLimit(const Limit& value, const Limit& cns) + { + assert(value.IsConstant()); + Limit result = value; + if (result.ShiftRightConstant(cns.GetConstant())) { - return Limit(Limit::keUnknown); + return result; } + return Limit(Limit::keUnknown); } // Given two ranges "r1" and "r2", perform an add operation on the @@ -311,20 +338,57 @@ struct RangeOps if (r1lo.IsConstant()) { - result.lLimit = AddConstantLimit(r1lo, r2lo); + result.lLimit = AddConstantLimit(r2lo, r1lo); } if (r2lo.IsConstant()) { - result.lLimit = AddConstantLimit(r2lo, r1lo); + result.lLimit = AddConstantLimit(r1lo, r2lo); } if (r1hi.IsConstant()) { - result.uLimit = AddConstantLimit(r1hi, r2hi); + result.uLimit = AddConstantLimit(r2hi, r1hi); } if (r2hi.IsConstant()) { - result.uLimit = AddConstantLimit(r2hi, r1hi); + result.uLimit = AddConstantLimit(r1hi, r2hi); + } + return result; + } + + static Range ShiftRight(Range& r1, Range& r2) + { + Limit& r1lo = r1.LowerLimit(); + Limit& r1hi = r1.UpperLimit(); + Limit& r2lo = r2.LowerLimit(); + Limit& r2hi = r2.UpperLimit(); + + Range result = Limit(Limit::keUnknown); + + // For now we only support r1 >> positive_cns (to simplify) + if (!r2lo.IsConstant() || !r2hi.IsConstant() || (r2lo.cns < 0) || (r2hi.cns < 0)) + { + return result; + } + + // Check lo ranges if they are dependent and not unknown. + if (r1lo.IsDependent()) + { + result.lLimit = Limit(Limit::keDependent); + } + else if (r1lo.IsConstant()) + { + result.lLimit = ShiftRightConstantLimit(r1lo, r2lo); + } + + if (r1hi.IsDependent()) + { + result.uLimit = Limit(Limit::keDependent); } + else if (r1hi.IsConstant()) + { + result.uLimit = ShiftRightConstantLimit(r1hi, r2hi); + } + return result; } @@ -352,19 +416,19 @@ struct RangeOps if (r1lo.IsConstant()) { - result.lLimit = MultiplyConstantLimit(r1lo, r2lo); + result.lLimit = MultiplyConstantLimit(r2lo, r1lo); } if (r2lo.IsConstant()) { - result.lLimit = MultiplyConstantLimit(r2lo, r1lo); + result.lLimit = MultiplyConstantLimit(r1lo, r2lo); } if (r1hi.IsConstant()) { - result.uLimit = MultiplyConstantLimit(r1hi, r2hi); + result.uLimit = MultiplyConstantLimit(r2hi, r1hi); } if (r2hi.IsConstant()) { - result.uLimit = MultiplyConstantLimit(r2hi, r1hi); + result.uLimit = MultiplyConstantLimit(r1hi, r2hi); } return result; } @@ -560,6 +624,9 @@ class RangeCheck // at phi definitions for the lower bound. Range GetRange(BasicBlock* block, GenTree* expr, bool monIncreasing DEBUGARG(int indent)); + // Compute the range from the given type + Range GetRangeFromType(var_types type); + // Given the local variable, first find the definition of the local and find the range of the rhs. // Helper for GetRange. Range ComputeRangeForLocalDef(BasicBlock* block, GenTreeLclVarCommon* lcl, bool monIncreasing DEBUGARG(int indent)); diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index e6b7e1a4d9234..4cb2d7261fab9 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -134,23 +134,6 @@ void Rationalizer::RewriteSIMDIndir(LIR::Use& use) addr->gtType = simdType; use.ReplaceWith(addr); } - else if (addr->OperIs(GT_ADDR)) - { - GenTree* location = addr->AsUnOp()->gtGetOp1(); - - if (location->OperIsSimdOrHWintrinsic() || location->IsCnsVec()) - { - // If we have IND(ADDR(SIMD)) then we can keep only the SIMD node. - // This is a special tree created by impNormStructVal to preserve the class layout - // needed by call morphing on an OBJ node. This information is no longer needed at - // this point (and the address of a SIMD node can't be obtained anyway). - - BlockRange().Remove(indir); - BlockRange().Remove(addr); - - use.ReplaceWith(addr->AsUnOp()->gtGetOp1()); - } - } #endif // FEATURE_SIMD } @@ -265,6 +248,62 @@ void Rationalizer::RewriteIntrinsicAsUserCall(GenTree** use, ArrayStack a % cns +// where cns is a signed integer constant that is a power of 2. +// We do this transformation because Lowering has a specific optimization +// for 'a % cns' that is not easily reduced by other means. +// +void Rationalizer::RewriteSubLshDiv(GenTree** use) +{ + if (!comp->opts.OptimizationEnabled()) + return; + + GenTree* const node = *use; + + if (!node->OperIs(GT_SUB)) + return; + + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + + if (!(node->TypeIs(TYP_INT, TYP_LONG) && op1->OperIs(GT_LCL_VAR))) + return; + + if (!op2->OperIs(GT_LSH)) + return; + + GenTree* lsh = op2; + GenTree* div = lsh->gtGetOp1(); + GenTree* shift = lsh->gtGetOp2(); + if (div->OperIs(GT_DIV) && shift->IsIntegralConst()) + { + GenTree* a = div->gtGetOp1(); + GenTree* cns = div->gtGetOp2(); + if (a->OperIs(GT_LCL_VAR) && cns->IsIntegralConstPow2() && + op1->AsLclVar()->GetLclNum() == a->AsLclVar()->GetLclNum()) + { + size_t shiftValue = shift->AsIntConCommon()->IntegralValue(); + size_t cnsValue = cns->AsIntConCommon()->IntegralValue(); + if ((cnsValue >> shiftValue) == 1) + { + node->ChangeOper(GT_MOD); + node->AsOp()->gtOp2 = cns; + BlockRange().Remove(lsh); + BlockRange().Remove(div); + BlockRange().Remove(a); + BlockRange().Remove(shift); + } + } + } +} +#endif + #ifdef DEBUG void Rationalizer::ValidateStatement(Statement* stmt, BasicBlock* block) @@ -524,6 +563,10 @@ void Rationalizer::RewriteAddress(LIR::Use& use) JITDUMP("Rewriting GT_ADDR(GT_IND(X)) to X:\n"); } + else + { + unreached(); + } DISPTREERANGE(BlockRange(), use.Def()); JITDUMP("\n"); @@ -556,13 +599,6 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge RewriteAssignment(use); break; - case GT_BOX: - case GT_ARR_ADDR: - // BOX/ARR_ADDR at this level are just NOPs. - use.ReplaceWith(node->gtGetOp1()); - BlockRange().Remove(node); - break; - case GT_ADDR: RewriteAddress(use); break; @@ -594,9 +630,11 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge break; case GT_NOP: - // fgMorph sometimes inserts NOP nodes between defs and uses - // supposedly 'to prevent constant folding'. In this case, remove the - // NOP. + case GT_BOX: + case GT_ARR_ADDR: + // "optNarrowTree" sometimes inserts NOP nodes between defs and uses. + // In this case, remove the NOP. BOX/ARR_ADDR are such "passthrough" + // nodes by design, and at this point we no longer need them. if (node->gtGetOp1() != nullptr) { use.ReplaceWith(node->gtGetOp1()); @@ -780,6 +818,13 @@ PhaseStatus Rationalizer::DoPhase() m_rationalizer.RewriteIntrinsicAsUserCall(use, this->m_ancestors); } +#ifdef TARGET_ARM64 + if (node->OperIs(GT_SUB)) + { + m_rationalizer.RewriteSubLshDiv(use); + } +#endif + return Compiler::WALK_CONTINUE; } diff --git a/src/coreclr/jit/rationalize.h b/src/coreclr/jit/rationalize.h index 47d355cbbd38f..329fbcbd1ac24 100644 --- a/src/coreclr/jit/rationalize.h +++ b/src/coreclr/jit/rationalize.h @@ -58,6 +58,10 @@ class Rationalizer final : public Phase void RewriteAssignment(LIR::Use& use); void RewriteAddress(LIR::Use& use); +#ifdef TARGET_ARM64 + void RewriteSubLshDiv(GenTree** use); +#endif + // Root visitor Compiler::fgWalkResult RewriteNode(GenTree** useEdge, Compiler::GenTreeStack& parents); }; diff --git a/src/coreclr/jit/scopeinfo.cpp b/src/coreclr/jit/scopeinfo.cpp index 6b2fcd5690eb6..b349d5e7aae64 100644 --- a/src/coreclr/jit/scopeinfo.cpp +++ b/src/coreclr/jit/scopeinfo.cpp @@ -295,7 +295,7 @@ void CodeGenInterface::siVarLoc::siFillStackVarLoc( case TYP_LONG: case TYP_DOUBLE: #endif // TARGET_64BIT -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#if FEATURE_IMPLICIT_BYREFS // In the AMD64 ABI we are supposed to pass a struct by reference when its // size is not 1, 2, 4 or 8 bytes in size. During fgMorph, the compiler modifies // the IR to comply with the ABI and therefore changes the type of the lclVar @@ -314,7 +314,7 @@ void CodeGenInterface::siVarLoc::siFillStackVarLoc( this->vlType = VLT_STK_BYREF; } else -#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) +#endif // FEATURE_IMPLICIT_BYREFS { this->vlType = VLT_STK; } diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp index 92706856a0dce..f0fc16be21c67 100644 --- a/src/coreclr/jit/simd.cpp +++ b/src/coreclr/jit/simd.cpp @@ -1207,7 +1207,7 @@ const SIMDIntrinsicInfo* Compiler::getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* in } // Pops and returns GenTree node from importer's type stack. -// Normalizes TYP_STRUCT value in case of GT_CALL, GT_RET_EXPR and arg nodes. +// Normalizes TYP_STRUCT value in case of GT_CALL and GT_RET_EXPR. // // Arguments: // type - the type of value that the caller expects to be popped off the stack. @@ -1219,7 +1219,7 @@ const SIMDIntrinsicInfo* Compiler::getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* in // Notes: // If the popped value is a struct, and the expected type is a simd type, it will be set // to that type, otherwise it will assert if the type being popped is not the expected type. - +// GenTree* Compiler::impSIMDPopStack(var_types type, bool expectAddr, CORINFO_CLASS_HANDLE structHandle) { StackEntry se = impPopStack(); @@ -1232,54 +1232,25 @@ GenTree* Compiler::impSIMDPopStack(var_types type, bool expectAddr, CORINFO_CLAS { assert(tree->TypeIs(TYP_BYREF, TYP_I_IMPL)); - if (tree->OperGet() == GT_ADDR) - { - tree = tree->gtGetOp1(); - } - else - { - tree = gtNewOperNode(GT_IND, type, tree); - } + tree = gtNewOperNode(GT_IND, type, tree); } - bool isParam = false; - - // If we are popping a struct type it must have a matching handle if one is specified. - // - If we have an existing 'OBJ' and 'structHandle' is specified, we will change its - // handle if it doesn't match. - // This can happen when we have a retyping of a vector that doesn't translate to any - // actual IR. - // - (If it's not an OBJ and it's used in a parameter context where it is required, - // impNormStructVal will add one). - // - if (tree->OperGet() == GT_OBJ) + if (tree->OperIsIndir() && tree->AsIndir()->Addr()->OperIs(GT_ADDR)) { - if ((structHandle != NO_CLASS_HANDLE) && (tree->AsObj()->GetLayout()->GetClassHandle() != structHandle)) + GenTree* location = tree->AsIndir()->Addr()->gtGetOp1(); + if (location->OperIs(GT_LCL_VAR) && location->TypeIs(type)) { - // In this case we need to retain the GT_OBJ to retype the value. - tree->AsObj()->SetLayout(typGetObjLayout(structHandle)); + assert(type != TYP_STRUCT); + tree = location; } - else - { - GenTree* addr = tree->AsOp()->gtOp1; - if ((addr->OperGet() == GT_ADDR) && isSIMDTypeLocal(addr->AsOp()->gtOp1)) - { - tree = addr->AsOp()->gtOp1; - } - } - } - - if (tree->OperGet() == GT_LCL_VAR) - { - isParam = lvaGetDesc(tree->AsLclVarCommon())->lvIsParam; } - // normalize TYP_STRUCT value - if (varTypeIsStruct(tree) && ((tree->OperGet() == GT_RET_EXPR) || (tree->OperGet() == GT_CALL) || isParam)) + // Handle calls that may return the struct via a return buffer. + if (varTypeIsStruct(tree) && tree->OperIs(GT_CALL, GT_RET_EXPR)) { assert(ti.IsType(TI_STRUCT)); - if (structHandle == nullptr) + if (structHandle == NO_CLASS_HANDLE) { structHandle = ti.GetClassHandleForValueClass(); } @@ -1685,7 +1656,15 @@ bool Compiler::areArrayElementsContiguous(GenTree* op1, GenTree* op2) // bool Compiler::areArgumentsContiguous(GenTree* op1, GenTree* op2) { - if (op1->OperIs(GT_IND) && op2->OperIs(GT_IND)) + if (op1->TypeGet() != op2->TypeGet()) + { + return false; + } + + assert(!op1->TypeIs(TYP_STRUCT)); + + if (op1->OperIs(GT_IND) && op1->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR) && op2->OperIs(GT_IND) && + op2->AsIndir()->Addr()->OperIs(GT_INDEX_ADDR)) { return areArrayElementsContiguous(op1, op2); } diff --git a/src/coreclr/jit/targetamd64.h b/src/coreclr/jit/targetamd64.h index ee2868fef4238..645d1933e3c5a 100644 --- a/src/coreclr/jit/targetamd64.h +++ b/src/coreclr/jit/targetamd64.h @@ -34,6 +34,7 @@ #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set #define MAX_PASS_SINGLEREG_BYTES 8 // Maximum size of a struct passed in a single register (double). #ifdef UNIX_AMD64_ABI + #define FEATURE_IMPLICIT_BYREFS 0 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register @@ -48,6 +49,7 @@ // This is also the maximum number of registers for a MultiReg node. #else // !UNIX_AMD64_ABI #define WINDOWS_AMD64_ABI // Uses the Windows ABI for AMD64 + #define FEATURE_IMPLICIT_BYREFS 1 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 0 // Support for returning a single value in more than one register diff --git a/src/coreclr/jit/targetarm.h b/src/coreclr/jit/targetarm.h index 8e93c1be08440..3e43eaa587141 100644 --- a/src/coreclr/jit/targetarm.h +++ b/src/coreclr/jit/targetarm.h @@ -23,6 +23,7 @@ #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls. #define FEATURE_SET_FLAGS 1 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set + #define FEATURE_IMPLICIT_BYREFS 0 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register (including HFA support) #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register (including passing HFAs) #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register (including HFA returns) diff --git a/src/coreclr/jit/targetarm64.h b/src/coreclr/jit/targetarm64.h index dbfd813ac090c..c9a1610aab2c5 100644 --- a/src/coreclr/jit/targetarm64.h +++ b/src/coreclr/jit/targetarm64.h @@ -28,6 +28,7 @@ #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls. #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set + #define FEATURE_IMPLICIT_BYREFS 1 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register diff --git a/src/coreclr/jit/targetloongarch64.h b/src/coreclr/jit/targetloongarch64.h index f704b4b256afb..4190420dc5b69 100644 --- a/src/coreclr/jit/targetloongarch64.h +++ b/src/coreclr/jit/targetloongarch64.h @@ -31,6 +31,7 @@ #define FEATURE_FASTTAILCALL 1 // Tail calls made as epilog+jmp #define FEATURE_TAILCALL_OPT 1 // opportunistic Tail calls (i.e. without ".tail" prefix) made as fast tail calls. #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when the flags need to be set + #define FEATURE_IMPLICIT_BYREFS 1 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register #define FEATURE_MULTIREG_ARGS 1 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register diff --git a/src/coreclr/jit/targetx86.h b/src/coreclr/jit/targetx86.h index 044b9f201d5e3..727275654930f 100644 --- a/src/coreclr/jit/targetx86.h +++ b/src/coreclr/jit/targetx86.h @@ -30,6 +30,7 @@ #define FEATURE_TAILCALL_OPT 0 // opportunistic Tail calls (without ".tail" prefix) made as fast tail calls. #define FEATURE_SET_FLAGS 0 // Set to true to force the JIT to mark the trees with GTF_SET_FLAGS when // the flags need to be set + #define FEATURE_IMPLICIT_BYREFS 0 // Support for struct parameters passed via pointers to shadow copies #define FEATURE_MULTIREG_ARGS_OR_RET 1 // Support for passing and/or returning single values in more than one register #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register diff --git a/src/coreclr/jit/unwind.cpp b/src/coreclr/jit/unwind.cpp index 6ad60a064f35c..63c4ed716cf39 100644 --- a/src/coreclr/jit/unwind.cpp +++ b/src/coreclr/jit/unwind.cpp @@ -69,7 +69,16 @@ void Compiler::unwindGetFuncLocations(FuncInfoDsc* func, // The hot section only goes up to the cold section assert(fgFirstFuncletBB == nullptr); - *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock)); +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting()) + { + *ppEndLoc = nullptr; // If fake-splitting, "trick" VM by pretending entire function is hot. + } + else +#endif // DEBUG + { + *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock)); + } } else { @@ -259,6 +268,13 @@ void Compiler::unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdC DWORD unwindCodeBytes = 0; BYTE* pUnwindBlock = nullptr; +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting()) + { + pColdCode = nullptr; + } +#endif // DEBUG + if (func->startLoc == nullptr) { startOffset = 0; diff --git a/src/coreclr/jit/unwindamd64.cpp b/src/coreclr/jit/unwindamd64.cpp index 2c8e90fa5a944..88cefbe31ed5e 100644 --- a/src/coreclr/jit/unwindamd64.cpp +++ b/src/coreclr/jit/unwindamd64.cpp @@ -656,18 +656,17 @@ void Compiler::unwindReserve() // void Compiler::unwindReserveFunc(FuncInfoDsc* func) { -#ifdef DEBUG - if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr)) + unwindReserveFuncHelper(func, true); + + if (fgFirstColdBlock != nullptr) { - assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets. - unwindReserveFuncHelper(func, true); - } - else +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting()) + { + assert(func->funKind == FUNC_ROOT); // No splitting of funclets. + } + else #endif // DEBUG - { - unwindReserveFuncHelper(func, true); - - if (fgFirstColdBlock != nullptr) { unwindReserveFuncHelper(func, false); } @@ -859,7 +858,17 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo if (isHotCode) { - assert(endOffset <= info.compTotalHotCodeSize); +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr)) + { + assert(endOffset <= info.compNativeCodeSize); + } + else +#endif // DEBUG + { + assert(endOffset <= info.compTotalHotCodeSize); + } + pColdCode = nullptr; } else @@ -890,43 +899,17 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER); static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER); -#ifdef DEBUG - if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr)) + unwindEmitFuncHelper(func, pHotCode, pColdCode, true); + + if (pColdCode != nullptr) { - fakeUnwindEmitFuncHelper(func, pHotCode); - } - else +#ifdef DEBUG + if (!JitConfig.JitFakeProcedureSplitting()) #endif // DEBUG - { - unwindEmitFuncHelper(func, pHotCode, pColdCode, true); - - if (pColdCode != nullptr) { unwindEmitFuncHelper(func, pHotCode, pColdCode, false); } } } -#ifdef DEBUG -void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode) -{ - assert(fgFirstColdBlock != nullptr); - assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets. - - const UNATIVE_OFFSET startOffset = 0; - const UNATIVE_OFFSET endOffset = info.compNativeCodeSize; - const DWORD unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot; - BYTE* pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot]; - - if (opts.dspUnwind) - { - DumpUnwindInfo(true, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock); - } - - // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section - eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, unwindCodeBytes, pUnwindBlock, - (CorJitFuncKind)func->funKind); -} -#endif // DEBUG - #endif // TARGET_AMD64 diff --git a/src/coreclr/jit/unwindarm.cpp b/src/coreclr/jit/unwindarm.cpp index 1eb7456250cbb..8a14c6edbb832 100644 --- a/src/coreclr/jit/unwindarm.cpp +++ b/src/coreclr/jit/unwindarm.cpp @@ -563,13 +563,20 @@ void Compiler::unwindReserve() void Compiler::unwindReserveFunc(FuncInfoDsc* func) { BOOL isFunclet = (func->funKind == FUNC_ROOT) ? FALSE : TRUE; - bool funcHasColdSection = false; + bool funcHasColdSection = (fgFirstColdBlock != nullptr); + +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting() && funcHasColdSection) + { + funcHasColdSection = false; // "Trick" the VM into thinking we don't have a cold section. + } +#endif // DEBUG #if defined(FEATURE_CFI_SUPPORT) if (generateCFIUnwindCodes()) { DWORD unwindCodeBytes = 0; - if (fgFirstColdBlock != nullptr) + if (funcHasColdSection) { eeReserveUnwindInfo(isFunclet, true /*isColdCode*/, unwindCodeBytes); } @@ -584,7 +591,7 @@ void Compiler::unwindReserveFunc(FuncInfoDsc* func) // cold section. This needs to be done before we split into fragments, as each // of the hot and cold sections can have multiple fragments. - if (fgFirstColdBlock != NULL) + if (funcHasColdSection) { assert(!isFunclet); // TODO-CQ: support hot/cold splitting with EH @@ -595,8 +602,6 @@ void Compiler::unwindReserveFunc(FuncInfoDsc* func) func->uwiCold = new (this, CMK_UnwindInfo) UnwindInfo(); func->uwiCold->InitUnwindInfo(this, startLoc, endLoc); func->uwiCold->HotColdSplitCodes(&func->uwi); - - funcHasColdSection = true; } // First we need to split the function or funclet into fragments that are no larger @@ -1604,11 +1609,19 @@ void UnwindFragmentInfo::Allocate( UNATIVE_OFFSET endOffset; UNATIVE_OFFSET codeSize; - // We don't support hot/cold splitting with EH, so if there is cold code, this - // better not be a funclet! - // TODO-CQ: support funclets in cold code - - noway_assert(isHotCode || funKind == CORJIT_FUNC_ROOT); +// We don't support hot/cold splitting with EH, so if there is cold code, this +// better not be a funclet! +// TODO-CQ: support funclets in cold code +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != NULL)) + { + noway_assert(isHotCode && (funKind == CORJIT_FUNC_ROOT)); + } + else +#endif // DEBUG + { + noway_assert(isHotCode || (funKind == CORJIT_FUNC_ROOT)); + } // Compute the final size, and start and end offsets of the fragment @@ -1656,7 +1669,17 @@ void UnwindFragmentInfo::Allocate( if (isHotCode) { - assert(endOffset <= uwiComp->info.compTotalHotCodeSize); +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != NULL)) + { + assert(endOffset <= uwiComp->info.compNativeCodeSize); + } + else +#endif // DEBUG + { + assert(endOffset <= uwiComp->info.compTotalHotCodeSize); + } + pColdCode = NULL; } else diff --git a/src/coreclr/jit/unwindx86.cpp b/src/coreclr/jit/unwindx86.cpp index bd27e46cbef49..32d077429af6a 100644 --- a/src/coreclr/jit/unwindx86.cpp +++ b/src/coreclr/jit/unwindx86.cpp @@ -113,18 +113,17 @@ void Compiler::unwindEmit(void* pHotCode, void* pColdCode) // void Compiler::unwindReserveFunc(FuncInfoDsc* func) { -#ifdef DEBUG - if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr)) + unwindReserveFuncHelper(func, true); + + if (fgFirstColdBlock != nullptr) { - assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets. - unwindReserveFuncHelper(func, true); - } - else +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting()) + { + assert(func->funKind == FUNC_ROOT); // No splitting of funclets. + } + else #endif // DEBUG - { - unwindReserveFuncHelper(func, true); - - if (fgFirstColdBlock != nullptr) { unwindReserveFuncHelper(func, false); } @@ -164,17 +163,13 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER); static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER); -#ifdef DEBUG - if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr)) + unwindEmitFuncHelper(func, pHotCode, pColdCode, true); + + if (pColdCode != nullptr) { - fakeUnwindEmitFuncHelper(func, pHotCode); - } - else +#ifdef DEBUG + if (!JitConfig.JitFakeProcedureSplitting()) #endif // DEBUG - { - unwindEmitFuncHelper(func, pHotCode, pColdCode, true); - - if (pColdCode != nullptr) { unwindEmitFuncHelper(func, pHotCode, pColdCode, false); } @@ -258,7 +253,17 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo if (isHotCode) { - assert(endOffset <= info.compTotalHotCodeSize); +#ifdef DEBUG + if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr)) + { + assert(endOffset <= info.compNativeCodeSize); + } + else +#endif // DEBUG + { + assert(endOffset <= info.compTotalHotCodeSize); + } + pColdCode = nullptr; } else @@ -276,22 +281,4 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo (BYTE*)&unwindInfo, (CorJitFuncKind)func->funKind); } -#ifdef DEBUG -void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode) -{ - assert(fgFirstColdBlock != nullptr); - assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets. - - const UNATIVE_OFFSET startOffset = 0; - const UNATIVE_OFFSET endOffset = info.compNativeCodeSize; - - UNWIND_INFO unwindInfo; - unwindInfo.FunctionLength = (ULONG)(endOffset); - - // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section - eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, sizeof(UNWIND_INFO), (BYTE*)&unwindInfo, - (CorJitFuncKind)func->funKind); -} -#endif // DEBUG - #endif // FEATURE_EH_FUNCLETS diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index be7fc14611f0f..3ec54f47e886f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -2869,13 +2869,15 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu { int resVal = EvalOp(func, ConstantValue(arg0VN)); // Unary op on a handle results in a handle. - return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetHandleFlags(arg0VN)) : VNForIntCon(resVal); + return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetFoldedArithOpResultHandleFlags(arg0VN)) + : VNForIntCon(resVal); } case TYP_LONG: { INT64 resVal = EvalOp(func, ConstantValue(arg0VN)); // Unary op on a handle results in a handle. - return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetHandleFlags(arg0VN)) : VNForLongCon(resVal); + return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetFoldedArithOpResultHandleFlags(arg0VN)) + : VNForLongCon(resVal); } case TYP_FLOAT: { @@ -3106,7 +3108,7 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu ValueNum handleVN = IsVNHandle(arg0VN) ? arg0VN : IsVNHandle(arg1VN) ? arg1VN : NoVN; if (handleVN != NoVN) { - result = VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)); // Use VN for Handle + result = VNForHandle(ssize_t(resultVal), GetFoldedArithOpResultHandleFlags(handleVN)); } else { @@ -3132,7 +3134,7 @@ ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, Valu if (handleVN != NoVN) { - result = VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)); // Use VN for Handle + result = VNForHandle(ssize_t(resultVal), GetFoldedArithOpResultHandleFlags(handleVN)); } else { @@ -4310,14 +4312,14 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN // Arguments: // block - BasicBlock where the expression that produces this value occurs. // May be nullptr to force conservative "could be anywhere" interpretation. -// typ - Type of the expression in the IR +// type - Type of the expression in the IR // // Return Value: // A new value number distinct from any previously generated, that compares as equal // to itself, but not any other value number, and is annotated with the given // type and block. - -ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types typ) +// +ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types type) { BasicBlock::loopNumber loopNum; if (block == nullptr) @@ -4331,7 +4333,7 @@ ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types typ) // VNForFunc(typ, func, vn) but bypasses looking in the cache // - Chunk* const c = GetAllocChunk(typ, CEA_Func1); + Chunk* const c = GetAllocChunk(type, CEA_Func1); unsigned const offsetWithinChunk = c->AllocVN(); VNDefFuncAppFlexible* fapp = c->PointerToFuncApp(offsetWithinChunk, 1); fapp->m_func = VNF_MemOpaque; @@ -4341,6 +4343,19 @@ ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types typ) return resultVN; } +//------------------------------------------------------------------------ +// VNPairForExpr - Create a "new, unique" pair of value numbers. +// +// "VNForExpr" equivalent for "ValueNumPair"s. +// +ValueNumPair ValueNumStore::VNPairForExpr(BasicBlock* block, var_types type) +{ + ValueNum uniqVN = VNForExpr(block, type); + ValueNumPair uniqVNP(uniqVN, uniqVN); + + return uniqVNP; +} + //------------------------------------------------------------------------ // VNForLoad: Get the VN for a load from a location (physical map). // @@ -5119,6 +5134,37 @@ GenTreeFlags ValueNumStore::GetHandleFlags(ValueNum vn) return handle->m_flags; } +GenTreeFlags ValueNumStore::GetFoldedArithOpResultHandleFlags(ValueNum vn) +{ + GenTreeFlags flags = GetHandleFlags(vn); + assert((flags & GTF_ICON_HDL_MASK) == flags); + + switch (flags) + { + case GTF_ICON_SCOPE_HDL: + case GTF_ICON_CLASS_HDL: + case GTF_ICON_METHOD_HDL: + case GTF_ICON_FIELD_HDL: + case GTF_ICON_TOKEN_HDL: + case GTF_ICON_STR_HDL: + case GTF_ICON_CONST_PTR: + case GTF_ICON_VARG_HDL: + case GTF_ICON_PINVKI_HDL: + case GTF_ICON_FTN_ADDR: + case GTF_ICON_CIDMID_HDL: + case GTF_ICON_TLS_HDL: + case GTF_ICON_STATIC_BOX_PTR: + return GTF_ICON_CONST_PTR; + case GTF_ICON_STATIC_HDL: + case GTF_ICON_GLOBAL_PTR: + case GTF_ICON_BBC_PTR: + return GTF_ICON_GLOBAL_PTR; + default: + assert(!"Unexpected handle type"); + return flags; + } +} + bool ValueNumStore::IsVNHandle(ValueNum vn) { if (vn == NoVN) @@ -8159,9 +8205,6 @@ void Compiler::fgValueNumberAssignment(GenTreeOp* tree) break; case GT_OBJ: - noway_assert(!"GT_OBJ can not be LHS when (tree->TypeGet() != TYP_STRUCT)!"); - break; - case GT_BLK: case GT_IND: { @@ -8457,8 +8500,7 @@ void Compiler::fgValueNumberTree(GenTree* tree) { unsigned lclNum = lclFld->GetLclNum(); - // TODO-ADDR: delete the "GetSize" check once location nodes are no more. - if (!lvaInSsa(lclFld->GetLclNum()) || !lclFld->HasSsaName() || (lclFld->GetSize() == 0)) + if (!lvaInSsa(lclFld->GetLclNum()) || !lclFld->HasSsaName()) { lclFld->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lclFld->TypeGet())); } @@ -9297,143 +9339,168 @@ void Compiler::fgValueNumberSimd(GenTreeSIMD* tree) #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS -// Does value-numbering for a GT_HWINTRINSIC node void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree) { - // For safety/correctness we must mutate the global heap valuenumber - // for any HW intrinsic that performs a memory store operation - if (tree->OperIsMemoryStore()) - { - fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); - } + NamedIntrinsic intrinsicId = tree->GetHWIntrinsicId(); + GenTree* addr = nullptr; + const bool isMemoryLoad = tree->OperIsMemoryLoad(&addr); + const bool isMemoryStore = !isMemoryLoad && tree->OperIsMemoryStore(&addr); - if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 2) == 2)) + // We do not model HWI stores precisely. + if (isMemoryStore) { - // 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 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; + fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore")); } - VNFunc func = GetVNFuncForNode(tree); - bool isMemoryLoad = tree->OperIsMemoryLoad(); + ValueNumPair excSetPair = ValueNumStore::VNPForEmptyExcSet(); + ValueNumPair normalPair = ValueNumPair(); - // If we have a MemoryLoad operation we will use the fgValueNumberByrefExposedLoad - // method to assign a value number that depends upon fgCurMemoryVN[ByrefExposed] ValueNumber - // - if (isMemoryLoad) + if ((tree->GetOperandCount() > 2) || ((JitConfig.JitDisableSimdVN() & 2) == 2)) { - 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. - // - ValueNum loadVN = fgValueNumberByrefExposedLoad(tree->TypeGet(), addrVN); - tree->gtVNPair.SetLiberal(loadVN); - tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet())); + // TODO-CQ: allow intrinsics with > 2 operands to be properly VN'ed. + normalPair = vnStore->VNPairForExpr(compCurBB, tree->TypeGet()); for (GenTree* operand : tree->Operands()) { - tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, vnStore->VNPExceptionSet(operand->gtVNPair)); + excSetPair = vnStore->VNPUnionExcSet(operand->gtVNPair, excSetPair); } - fgValueNumberAddExceptionSetForIndirection(tree, tree->Op(1)); - return; } - - bool encodeResultType = vnEncodesResultTypeForHWIntrinsic(tree->GetHWIntrinsicId()); - - ValueNumPair excSetPair = ValueNumStore::VNPForEmptyExcSet(); - ValueNumPair normalPair; - ValueNumPair resvnp = ValueNumPair(); - - if (encodeResultType) + else { - ValueNum simdTypeVN = vnStore->VNForSimdType(tree->GetSimdSize(), tree->GetNormalizedSimdBaseJitType()); - resvnp.SetBoth(simdTypeVN); + VNFunc func = GetVNFuncForNode(tree); + ValueNumPair resultTypeVNPair = ValueNumPair(); + bool encodeResultType = vnEncodesResultTypeForHWIntrinsic(intrinsicId); -#ifdef DEBUG - if (verbose) + if (encodeResultType) { - printf(" simdTypeVN is "); - vnPrint(simdTypeVN, 1); - printf("\n"); + ValueNum simdTypeVN = vnStore->VNForSimdType(tree->GetSimdSize(), tree->GetNormalizedSimdBaseJitType()); + resultTypeVNPair.SetBoth(simdTypeVN); + + JITDUMP(" simdTypeVN is "); + JITDUMPEXEC(vnPrint(simdTypeVN, 1)); + JITDUMP("\n"); } -#endif - } - const bool isVariableNumArgs = HWIntrinsicInfo::lookupNumArgs(tree->GetHWIntrinsicId()) == -1; + auto getOperandVNs = [this, addr](GenTree* operand, ValueNumPair* pNormVNPair, ValueNumPair* pExcVNPair) { + vnStore->VNPUnpackExc(operand->gtVNPair, pNormVNPair, pExcVNPair); - // There are some HWINTRINSICS operations that have zero args, i.e. NI_Vector128_Zero - if (tree->GetOperandCount() == 0) - { - // Currently we don't have intrinsics with variable number of args with a parameter-less option. - assert(!isVariableNumArgs); + // If we have a load operation we will use the fgValueNumberByrefExposedLoad + // method to assign a value number that depends upon the current heap state. + // + if (operand == addr) + { + // We need to "insert" the "ByrefExposedLoad" VN somewhere here. We choose + // to do so by effectively altering the semantics of "addr" operands, making + // them represent "the load", on top of which the HWI func itself is applied. + // This is a workaround, but doing this "properly" would entail adding the + // heap and type VNs to HWI load funcs themselves. + var_types loadType = operand->TypeGet(); + ValueNum loadVN = fgValueNumberByrefExposedLoad(loadType, pNormVNPair->GetLiberal()); - if (encodeResultType) - { - // There are zero arg HWINTRINSICS operations that encode the result type, i.e. Vector128_AllBitSet - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, resvnp); - assert(vnStore->VNFuncArity(func) == 1); - } - else - { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func); - assert(vnStore->VNFuncArity(func) == 0); - } - } - else // HWINTRINSIC unary or binary operator. - { - ValueNumPair op1vnp; - ValueNumPair op1Xvnp; - vnStore->VNPUnpackExc(tree->Op(1)->gtVNPair, &op1vnp, &op1Xvnp); + pNormVNPair->SetLiberal(loadVN); + pNormVNPair->SetConservative(vnStore->VNForExpr(compCurBB, loadType)); + } + }; - if (tree->GetOperandCount() == 1) + const bool isVariableNumArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicId) == -1; + + // There are some HWINTRINSICS operations that have zero args, i.e. NI_Vector128_Zero + if (tree->GetOperandCount() == 0) { - excSetPair = op1Xvnp; + // Currently we don't have intrinsics with variable number of args with a parameter-less option. + assert(!isVariableNumArgs); if (encodeResultType) { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, resvnp); - assert((vnStore->VNFuncArity(func) == 2) || isVariableNumArgs); + // There are zero arg HWINTRINSICS operations that encode the result type, i.e. Vector128_AllBitSet + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, resultTypeVNPair); + assert(vnStore->VNFuncArity(func) == 1); } else { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp); - assert((vnStore->VNFuncArity(func) == 1) || isVariableNumArgs); + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func); + assert(vnStore->VNFuncArity(func) == 0); } } - else + else // HWINTRINSIC unary or binary operator. { - ValueNumPair op2vnp; - ValueNumPair op2Xvnp; - vnStore->VNPUnpackExc(tree->Op(2)->gtVNPair, &op2vnp, &op2Xvnp); + ValueNumPair op1vnp; + ValueNumPair op1Xvnp; + getOperandVNs(tree->Op(1), &op1vnp, &op1Xvnp); - excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp); - if (encodeResultType) + if (tree->GetOperandCount() == 1) { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, op2vnp, resvnp); - assert((vnStore->VNFuncArity(func) == 3) || isVariableNumArgs); + excSetPair = op1Xvnp; + + if (encodeResultType) + { + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, resultTypeVNPair); + assert((vnStore->VNFuncArity(func) == 2) || isVariableNumArgs); + } + else + { + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp); + assert((vnStore->VNFuncArity(func) == 1) || isVariableNumArgs); + } } else { - normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, op2vnp); - assert((vnStore->VNFuncArity(func) == 2) || isVariableNumArgs); + ValueNumPair op2vnp; + ValueNumPair op2Xvnp; + getOperandVNs(tree->Op(2), &op2vnp, &op2Xvnp); + + excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp); + if (encodeResultType) + { + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, op2vnp, resultTypeVNPair); + assert((vnStore->VNFuncArity(func) == 3) || isVariableNumArgs); + } + else + { + normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, op2vnp); + assert((vnStore->VNFuncArity(func) == 2) || isVariableNumArgs); + } } } } + tree->gtVNPair = vnStore->VNPWithExc(normalPair, excSetPair); + + // Currently, the only exceptions these intrinsics could throw are NREs. + // + if (isMemoryLoad || isMemoryStore) + { + // Most load operations are simple "IND(addr)" equivalents. However, there are exceptions such as AVX + // "gather" operations, where the "effective" address - one from which the actual load will be performed and + // NullReferenceExceptions are associated with does not match the value of "addr". We will punt handling those + // precisely for now. + switch (intrinsicId) + { +#ifdef TARGET_XARCH + case NI_SSE2_MaskMove: + case NI_AVX_MaskStore: + case NI_AVX2_MaskStore: + case NI_AVX_MaskLoad: + case NI_AVX2_MaskLoad: + case NI_AVX2_GatherVector128: + case NI_AVX2_GatherVector256: + case NI_AVX2_GatherMaskVector128: + case NI_AVX2_GatherMaskVector256: + { + ValueNumPair uniqAddrVNPair = vnStore->VNPairForExpr(compCurBB, TYP_BYREF); + ValueNumPair uniqExcVNPair = vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, uniqAddrVNPair); + ValueNumPair uniqExcSetVNPair = vnStore->VNPExcSetSingleton(uniqExcVNPair); + + tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, uniqExcSetVNPair); + } + break; +#endif // TARGET_XARCH + + default: + fgValueNumberAddExceptionSetForIndirection(tree, addr); + break; + } + } } #endif // FEATURE_HW_INTRINSICS @@ -9650,19 +9717,14 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN vnpUniq.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet())); } -#if defined(FEATURE_READYTORUN) && (defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64)) - if (call->IsR2RRelativeIndir()) + if (call->GetIndirectionCellArgKind() != WellKnownArg::None) { -#ifdef DEBUG - GenTree* indirectCellAddress = args->GetArgByIndex(0)->GetNode(); - assert(indirectCellAddress->IsCnsIntOrI() && indirectCellAddress->GetRegNum() == REG_R2R_INDIRECT_PARAM); -#endif // DEBUG - - // For ARM indirectCellAddress is consumed by the call itself, so it should have added as an implicit argument - // in morph. So we do not need to use EntryPointAddrAsArg0, because arg0 is already an entry point addr. + // If we are VN'ing a call with indirection cell arg (e.g. because this + // is a helper in a R2R compilation) then morph should already have + // added this arg, so we do not need to use EntryPointAddrAsArg0 + // because the indirection cell itself allows us to disambiguate. useEntryPointAddrAsArg0 = false; } -#endif // FEATURE_READYTORUN && (TARGET_ARMARCH || TARGET_LOONGARCH64) CallArg* curArg = &*args->Args().begin(); if (nArgs == 0) diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 22755856066a7..4741e6150debe 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -379,6 +379,8 @@ class ValueNumStore // returns true iff vn is known to be a constant int32 that is > 0 bool IsVNPositiveInt32Constant(ValueNum vn); + GenTreeFlags GetFoldedArithOpResultHandleFlags(ValueNum vn); + public: // Initializes any static variables of ValueNumStore. static void InitValueNumStoreStatics(); @@ -685,9 +687,8 @@ class ValueNumStore op3VN.GetConservative(), op4VN.GetConservative())); } - // Get a new, unique value number for an expression that we're not equating to some function, - // which is the value of a tree in the given block. - ValueNum VNForExpr(BasicBlock* block, var_types typ = TYP_UNKNOWN); + ValueNum VNForExpr(BasicBlock* block, var_types type = TYP_UNKNOWN); + ValueNumPair VNPairForExpr(BasicBlock* block, var_types type); // This controls extra tracing of the "evaluation" of "VNF_MapSelect" functions. #define FEATURE_VN_TRACE_APPLY_SELECTORS 1 diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index b76139fdb604f..57ce0c09f283d 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -23,6 +23,18 @@ #if defined(TARGET_OSX) && defined(TARGET_AMD64) #include +#include + +bool IsProcessTranslated() +{ + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) + { + return false; + } + return ret == 1; +} #endif // TARGET_OSX && TARGET_AMD64 #ifndef TARGET_OSX @@ -65,6 +77,15 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu *pMaxExecutableCodeSize = MaxDoubleMappedSize; *pHandle = (void*)(size_t)fd; #else // !TARGET_OSX + +#ifdef TARGET_AMD64 + if (IsProcessTranslated()) + { + // Rosetta doesn't support double mapping correctly + return false; + } +#endif // TARGET_AMD64 + *pMaxExecutableCodeSize = SIZE_MAX; *pHandle = NULL; #endif // !TARGET_OSX diff --git a/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj b/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj index 624760868cf2d..a70f6a4f801b6 100644 --- a/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj +++ b/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj @@ -11,6 +11,11 @@ + + + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props index b150bf6392cb2..c8ef6487bd504 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props @@ -89,7 +89,6 @@ The .NET Foundation licenses this file to you under the MIT license. - diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props index d8c01d5a199cf..e0e595e2f8c98 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props @@ -86,6 +86,12 @@ The .NET Foundation licenses this file to you under the MIT license. + + + + + + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index d5c08a768d970..9f079b4323fb8 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -46,7 +46,6 @@ The .NET Foundation licenses this file to you under the MIT license. - false true false @@ -109,8 +108,7 @@ The .NET Foundation licenses this file to you under the MIT license. - <_ExcludedPrivateSdkAssemblies Include="$(IlcSdkPath)System.Private.Reflection.Core.dll" Condition="$(IlcDisableReflection) == 'true'" /> - + @@ -150,8 +148,7 @@ The .NET Foundation licenses this file to you under the MIT license. - <_ExcludedPrivateSdkAssemblies Include="$(IlcSdkPath)System.Private.Reflection.Core.dll" Condition="$(IlcDisableReflection) == 'true'" /> - + @@ -235,14 +232,14 @@ The .NET Foundation licenses this file to you under the MIT license. - + - + diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs index 07dd95f67c980..6a56d48790efc 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs @@ -1499,7 +1499,7 @@ public IntPtr Value // Wrapper around pointers [StructLayout(LayoutKind.Sequential)] - internal unsafe readonly struct Pointer where T : unmanaged + internal readonly unsafe struct Pointer where T : unmanaged { private readonly T* _value; @@ -1514,7 +1514,7 @@ public T* Value // Wrapper around pointers that might be indirected through IAT [StructLayout(LayoutKind.Sequential)] - internal unsafe readonly struct IatAwarePointer where T : unmanaged + internal readonly unsafe struct IatAwarePointer where T : unmanaged { private readonly T* _value; @@ -1546,7 +1546,7 @@ public unsafe IntPtr Value // Wrapper around relative pointers [StructLayout(LayoutKind.Sequential)] - internal unsafe readonly struct RelativePointer where T : unmanaged + internal readonly unsafe struct RelativePointer where T : unmanaged { private readonly int _value; @@ -1561,7 +1561,7 @@ public T* Value // Wrapper around relative pointers that might be indirected through IAT [StructLayout(LayoutKind.Sequential)] - internal unsafe readonly struct IatAwareRelativePointer where T : unmanaged + internal readonly unsafe struct IatAwareRelativePointer where T : unmanaged { private readonly int _value; diff --git a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs deleted file mode 100644 index f7d6a1d315f84..0000000000000 --- a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs +++ /dev/null @@ -1,46 +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; - -namespace System.Runtime.CompilerServices -{ - // - // Attach to classes that contain code only used in ILC /BuildType:chk builds. - // - // Any class attributed with this must have the following properties: - // - // - Class must be declared "static" - // - // - All public/internal methods must have a return type of: - // - // void - // bool - // any non-value type - // - // - All fields must be private. - // - // - Class constructor must not have externally visible side effects. - // - // - // On /BuildType:ret builds, ILC will run a special transform that - // turns all of the public and internal method bodies into - // the equivalent of: - // - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // T Foo() - // { - // return default(T); - // } - // - // It also removes all fields and private methods (including the class constructor.) - // - // The method semantics must be defined so that ret builds have - // the desired behavior with these implementations. - // - // - [AttributeUsage(AttributeTargets.Class)] - internal sealed class DeveloperExperienceModeOnlyAttribute : Attribute - { - } -} diff --git a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceState.cs b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceState.cs index f2e0d260b5d12..78a8de127e59f 100644 --- a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceState.cs +++ b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceState.cs @@ -5,7 +5,6 @@ namespace System.Runtime.CompilerServices { - [DeveloperExperienceModeOnly] internal static class DeveloperExperienceState { public static bool DeveloperExperienceModeEnabled diff --git a/src/coreclr/nativeaot/Directory.Build.props b/src/coreclr/nativeaot/Directory.Build.props index b2cbc3c9bd2b1..bd21f742967a1 100644 --- a/src/coreclr/nativeaot/Directory.Build.props +++ b/src/coreclr/nativeaot/Directory.Build.props @@ -34,7 +34,7 @@ $(NoWarn);CS8602;CS8603;CS8604;CS8618;CS8625;CS8632;CS8765 - $(NoWarn);CA1810;CA1823;CA1825;CA1852;CA2208;SA1129;SA1205;SA1400;SA1517 + $(NoWarn);CA1810;CA1823;CA1825;CA1852;CA2208;SA1129;SA1205;SA1400;SA1517;IDE0065 $(NoWarn);CS3016 diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs index 3b081e5d64cfc..b277d80d79784 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs @@ -303,7 +303,7 @@ public static unsafe int RhGetCurrentThreadStackTrace(IntPtr[] outputBuffer) // Use DllImport here instead of LibraryImport because this file is used by Test.CoreLib. [DllImport(Redhawk.BaseName)] [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] - private static unsafe extern int RhpGetCurrentThreadStackTrace(IntPtr* pOutputBuffer, uint outputBufferLength, UIntPtr addressInCurrentFrame); + private static extern unsafe int RhpGetCurrentThreadStackTrace(IntPtr* pOutputBuffer, uint outputBufferLength, UIntPtr addressInCurrentFrame); // Worker for RhGetCurrentThreadStackTrace. RhGetCurrentThreadStackTrace just allocates a transition // frame that will be used to seed the stack trace and this method does all the real work. diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs index 76234dde14e4d..62c26ccd305ef 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs @@ -217,7 +217,7 @@ public unsafe IntPtr AllocateThunk() int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.PageSizeMask)); Debug.Assert((thunkIndex % Constants.ThunkDataSize) == 0); - thunkIndex = thunkIndex / Constants.ThunkDataSize; + thunkIndex /= Constants.ThunkDataSize; IntPtr thunkAddress = InternalCalls.RhpGetThunkStubsBlockAddress(nextAvailableThunkPtr) + thunkIndex * Constants.ThunkCodeSize; diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index 8ce6ea0d29672..3ad3ceba7c8f0 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -245,10 +245,7 @@ add_definitions(-D_LIB) if(WIN32) add_definitions(-DFEATURE_ETW) add_definitions(-DFEATURE_EVENT_TRACE) - # redirection on ARM64 should work, but needs to be tested - if (CLR_CMAKE_TARGET_ARCH_AMD64) - add_definitions(-DFEATURE_SUSPEND_REDIRECTION) - endif() + add_definitions(-DFEATURE_SUSPEND_REDIRECTION) else() add_definitions(-DNO_UI_ASSERT) include(unix/configure.cmake) diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index e65889cd3fc54..2d8d3b2b2baa2 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -60,6 +60,30 @@ int g_cpuFeatures = 0; EXTERN_C int g_requiredCpuFeatures; #endif +#ifdef TARGET_UNIX +static bool InitGSCookie(); + +//----------------------------------------------------------------------------- +// GSCookies (guard-stack cookies) for detecting buffer overruns +//----------------------------------------------------------------------------- + +#ifdef __APPLE__ +#define READONLY_ATTR_ARGS section("__DATA,__const") +#else +#define READONLY_ATTR_ARGS section(".rodata") +#endif +#define READONLY_ATTR __attribute__((READONLY_ATTR_ARGS)) + +// Guard-stack cookie for preventing against stack buffer overruns +typedef size_t GSCookie; + +// const is so that it gets placed in the .text section (which is read-only) +// volatile is so that accesses to it do not get optimized away because of the const +// + +extern "C" volatile READONLY_ATTR const GSCookie __security_cookie = 0; +#endif // TARGET_UNIX + static bool InitDLL(HANDLE hPalInstance) { #ifdef FEATURE_CACHED_INTERFACE_DISPATCH @@ -119,6 +143,11 @@ static bool InitDLL(HANDLE hPalInstance) return false; #endif +#ifdef TARGET_UNIX + if (!InitGSCookie()) + return false; +#endif + if (!g_CastCacheLock.InitNoThrow(CrstType::CrstCastCache)) return false; @@ -275,6 +304,34 @@ bool DetectCPUFeatures() } #endif // !USE_PORTABLE_HELPERS +#ifdef TARGET_UNIX +inline +GSCookie * GetProcessGSCookiePtr() { return const_cast(&__security_cookie); } + +bool InitGSCookie() +{ + volatile GSCookie * pGSCookiePtr = GetProcessGSCookiePtr(); + + // The GS cookie is stored in a read only data segment + if (!PalVirtualProtect((void*)pGSCookiePtr, sizeof(GSCookie), PAGE_READWRITE)) + { + return false; + } + + // REVIEW: Need something better for PAL... + GSCookie val = (GSCookie)PalGetTickCount64(); + +#ifdef _DEBUG + // In _DEBUG, always use the same value to make it easier to search for the cookie + val = (GSCookie)(0x9ABCDEF012345678); +#endif + + *pGSCookiePtr = val; + + return PalVirtualProtect((void*)pGSCookiePtr, sizeof(GSCookie), PAGE_READONLY); +} +#endif // TARGET_UNIX + #ifdef PROFILE_STARTUP #define STD_OUTPUT_HANDLE ((uint32_t)-11) diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index df0dc0a20339c..aa5cfeb3cde21 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -734,6 +734,9 @@ static int W32toUnixAccessControl(uint32_t flProtect) case PAGE_EXECUTE_READWRITE: prot = PROT_READ | PROT_WRITE | PROT_EXEC; break; + case PAGE_READONLY: + prot = PROT_READ; + break; default: ASSERT(false); break; @@ -812,7 +815,11 @@ REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalVirtualProtect(_In_ void* pAddre { int unixProtect = W32toUnixAccessControl(protect); - return mprotect(pAddress, size, unixProtect) == 0; + // mprotect expects the address to be page-aligned + uint8_t* pPageStart = ALIGN_DOWN((uint8_t*)pAddress, OS_PAGE_SIZE); + size_t memSize = ALIGN_UP((uint8_t*)pAddress + size, OS_PAGE_SIZE) - pPageStart; + + return mprotect(pPageStart, memSize, unixProtect) == 0; } REDHAWK_PALEXPORT _Ret_maybenull_ void* REDHAWK_PALAPI PalSetWerDataBuffer(_In_ void* pNewBuffer) diff --git a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp index 4010dbea5241f..7738a7455c757 100644 --- a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp @@ -693,7 +693,6 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn PTR_PTR_VOID * ppvRetAddrLocation, // out GCRefKind * pRetValueKind) // out { -#if defined(TARGET_AMD64) CoffNativeMethodInfo * pNativeMethodInfo = (CoffNativeMethodInfo *)pMethodInfo; size_t unwindDataBlobSize; @@ -719,7 +718,11 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn p += sizeof(int32_t); // Decode the GC info for the current method to determine its return type - GcInfoDecoder decoder(GCInfoToken(p), DECODE_RETURN_KIND); + GcInfoDecoderFlags flags = DECODE_RETURN_KIND; +#if defined(TARGET_ARM) || defined(TARGET_ARM64) + flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS); +#endif // TARGET_ARM || TARGET_ARM64 + GcInfoDecoder decoder(GCInfoToken(p), flags); GCRefKind gcRefKind = GetGcRefKind(decoder.GetReturnKind()); @@ -728,6 +731,11 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn SIZE_T EstablisherFrame; PVOID HandlerData; CONTEXT context; +#ifdef _DEBUG + memset(&context, 0xDD, sizeof(context)); +#endif + +#if defined(TARGET_AMD64) context.Rsp = pRegisterSet->GetSP(); context.Rbp = pRegisterSet->GetFP(); context.Rip = pRegisterSet->GetIP(); @@ -744,6 +752,55 @@ bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodIn *ppvRetAddrLocation = (PTR_PTR_VOID)(context.Rsp - sizeof (PVOID)); *pRetValueKind = gcRefKind; return true; +#elif defined(TARGET_ARM64) + + if (decoder.HasTailCalls()) + { + // Do not hijack functions that have tail calls, since there are two problems: + // 1. When a function that tail calls another one is hijacked, the LR may be + // stored at a different location in the stack frame of the tail call target. + // So just by performing tail call, the hijacked location becomes invalid and + // unhijacking would corrupt stack by writing to that location. + // 2. There is a small window after the caller pops LR from the stack in its + // epilog and before the tail called function pushes LR in its prolog when + // the hijacked return address would not be not on the stack and so we would + // not be able to unhijack. + return false; + } + + context.Sp = pRegisterSet->GetSP(); + context.Fp = pRegisterSet->GetFP(); + context.Pc = pRegisterSet->GetIP(); + context.Lr = *pRegisterSet->pLR; + + KNONVOLATILE_CONTEXT_POINTERS contextPointers; +#ifdef _DEBUG + memset(&contextPointers, 0xDD, sizeof(contextPointers)); +#endif + contextPointers.Lr = pRegisterSet->pLR; + + RtlVirtualUnwind(NULL, + dac_cast(m_moduleBase), + pRegisterSet->IP, + (PRUNTIME_FUNCTION)pNativeMethodInfo->runtimeFunction, + &context, + &HandlerData, + &EstablisherFrame, + &contextPointers); + + if (contextPointers.Lr == pRegisterSet->pLR) + { + // This is the case when we are either: + // + // 1) In a leaf method that does not push LR on stack, OR + // 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack + // or has LR already popped off. + return false; + } + + *ppvRetAddrLocation = (PTR_PTR_VOID)contextPointers.Lr; + *pRetValueKind = gcRefKind; + return true; #else return false; #endif // defined(TARGET_AMD64) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml index 3aeeaf70faefd..48edfc4f2540c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml @@ -17,4 +17,7 @@ + + + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs index 0499890c36ac6..a6d77cbedf7cd 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs @@ -100,7 +100,7 @@ public virtual void TryGetMethodBase(IntPtr methodStartAddress, out MethodBase m public virtual bool OnContractFailure(string? stackTrace, ContractFailureKind contractFailureKind, string? displayMessage, string userMessage, string conditionText, Exception innerException) { - Debug.WriteLine("Assertion failed: " + (displayMessage == null ? "" : displayMessage)); + Debug.WriteLine("Assertion failed: " + (displayMessage ?? "")); if (Debugger.IsAttached) Debugger.Break(); return false; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Reflection/Core/AssemblyBinder.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/AssemblyBinder.cs similarity index 92% rename from src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Reflection/Core/AssemblyBinder.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/AssemblyBinder.cs index 0a7bab62ea362..f68d8407b2781 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Reflection/Core/AssemblyBinder.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/AssemblyBinder.cs @@ -6,12 +6,15 @@ using System.Reflection; using Internal.Metadata.NativeFormat; using System.Reflection.Runtime.General; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Internal.Reflection.Core { // Auto StructLayout used to suppress warning that order of fields is not guaranteed in partial structs [StructLayout(LayoutKind.Auto)] + [ReflectionBlocked] + [CLSCompliant(false)] public partial struct AssemblyBindResult { public MetadataReader Reader; @@ -25,6 +28,8 @@ public partial struct AssemblyBindResult // // If the binder cannot locate an assembly, it must return null and set "exception" to an exception object. // + [ReflectionBlocked] + [CLSCompliant(false)] public abstract class AssemblyBinder { public const string DefaultAssemblyNameForGetType = "System.Private.CoreLib"; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs index f2065074d78b3..02f6a206015db 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs @@ -16,6 +16,7 @@ #endif using System.Reflection.Runtime.TypeParsing; using System.Reflection.Runtime.CustomAttributes; +using System.Runtime.CompilerServices; using Internal.Metadata.NativeFormat; using Internal.Runtime.Augments; @@ -24,6 +25,8 @@ namespace Internal.Reflection.Core.Execution // // This singleton class acts as an entrypoint from System.Private.Reflection.Execution to System.Private.Reflection.Core. // + [ReflectionBlocked] + [CLSCompliant(false)] public sealed class ExecutionDomain { internal ExecutionDomain(ReflectionDomainSetup executionDomainSetup, ExecutionEnvironment executionEnvironment) @@ -124,7 +127,7 @@ private static CoreTypeResolver CreateCoreTypeResolver(Func - @@ -344,9 +343,15 @@ + + ArrayBuilder.cs + Utilities\LockFreeReaderHashtable.cs + + System\Collections\Generic\EnumerableExtensions.cs + System\Collections\Generic\LowLevelList.cs @@ -374,6 +379,9 @@ System\Runtime\CompilerServices\__BlockReflectionAttribute.cs + + System\Runtime\CompilerServices\DeveloperExperienceState.cs + Internal\Runtime\CanonTypeKind.cs @@ -398,6 +406,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/ActivatorImplementation.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ActivatorImplementation.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/ActivatorImplementation.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/ActivatorImplementation.cs index 4370581bd7c6e..8e3aef57b8ca5 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/ActivatorImplementation.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ActivatorImplementation.cs @@ -28,7 +28,7 @@ public static object CreateInstance( BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; if (nonPublic) bindingFlags |= BindingFlags.NonPublic; - ConstructorInfo constructor = type.GetConstructor(bindingFlags, null, CallingConventions.Any, Array.Empty(), null); + ConstructorInfo? constructor = type.GetConstructor(bindingFlags, null, CallingConventions.Any, Array.Empty(), null); if (constructor == null) { if (type.IsValueType) @@ -44,7 +44,7 @@ public static object CreateInstance( [DebuggerGuidedStepThrough] public static object CreateInstance( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) + Type type, BindingFlags bindingAttr, Binder binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) { if (type == null) throw new ArgumentNullException(nameof(type)); @@ -64,7 +64,7 @@ public static object CreateInstance( args = Array.Empty(); int numArgs = args.Length; - Type[] argTypes = new Type[numArgs]; + Type?[] argTypes = new Type[numArgs]; for (int i = 0; i < numArgs; i++) { argTypes[i] = args[i]?.GetType(); @@ -88,7 +88,7 @@ public static object CreateInstance( if (binder == null) binder = Type.DefaultBinder; - MethodBase invokeMethod = binder.BindToMethod(bindingAttr, matches.ToArray(), ref args, null, culture, null, out object state); + MethodBase invokeMethod = binder.BindToMethod(bindingAttr, matches.ToArray(), ref args, null, culture, null, out object? state); if (invokeMethod.GetParametersNoCopy().Length == 0) { if (args.Length != 0) @@ -132,7 +132,7 @@ private static void CreateInstanceCheckType(Type type) Type elementType = type; while (elementType.HasElementType) - elementType = elementType.GetElementType(); + elementType = elementType.GetElementType()!; if (elementType == typeof(void)) throw new NotSupportedException(SR.Acc_CreateVoid); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index 69b2f50c74f53..08725d5744774 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -897,7 +897,7 @@ internal static unsafe Array NewMultiDimArray(EETypePtr eeType, int* pLengths, i throw new OverflowException(); if (length > MaxLength) maxArrayDimensionLengthOverflow = true; - totalLength = totalLength * (ulong)length; + totalLength *= (ulong)length; if (totalLength > int.MaxValue) throw new OutOfMemoryException(); // "Array dimensions exceeded supported range." } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs index 2573576699927..c5648c28885a3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs @@ -65,10 +65,17 @@ internal static void ShutdownCore() public static int TickCount => (int)TickCount64; + private static string[]? s_commandLineArgs; + public static string[] GetCommandLineArgs() { Debug.Assert(s_commandLineArgs != null, "VM did not properly setup application."); return (string[])s_commandLineArgs.Clone(); } + + internal static void SetCommandLineArgs(string[] cmdLineArgs) + { + s_commandLineArgs = cmdLineArgs; + } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Helpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Helpers.cs deleted file mode 100644 index 23a17a0e6702c..0000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Helpers.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// Implements System.Type -// - -using System; -using Internal.Runtime.Augments; - -namespace System -{ - internal static class Helpers - { - public static bool TryGetEEType(this Type type, out EETypePtr eeType) - { - RuntimeTypeHandle typeHandle = RuntimeAugments.Callbacks.GetTypeHandleIfAvailable(type); - if (typeHandle.IsNull) - { - eeType = default(EETypePtr); - return false; - } - eeType = typeHandle.ToEETypePtr(); - return true; - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs index 6d5e6e5f937e6..9b6b704cb68fa 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/MulticastDelegate.cs @@ -46,7 +46,7 @@ private bool InvocationListEquals(MulticastDelegate d) return true; } - public override sealed bool Equals([NotNullWhen(true)] object? obj) + public sealed override bool Equals([NotNullWhen(true)] object? obj) { if (obj == null) return false; @@ -90,7 +90,7 @@ public override sealed bool Equals([NotNullWhen(true)] object? obj) } } - public override sealed int GetHashCode() + public sealed override int GetHashCode() { Delegate[]? invocationList = m_helperObject as Delegate[]; if (invocationList == null) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs index b5e8e0dc0230f..49190e8c37125 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs @@ -21,7 +21,7 @@ public virtual int ILOffset } } - public virtual void BeginCatchBlock(Type exceptionType) + public virtual void BeginCatchBlock(Type? exceptionType) { } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs index d9f9c5f7148e2..48a2198d49bfe 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseInsensitive.cs @@ -90,7 +90,7 @@ private LowLevelDictionary CreateCaseInsensitiveTypeDictionary( { string ns = namespaceHandle.ToNamespaceName(reader); if (ns.Length != 0) - ns = ns + "."; + ns += "."; ns = ns.ToLowerInvariant(); NamespaceDefinition namespaceDefinition = namespaceHandle.GetNamespaceDefinition(reader); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.GetTypeCore.CaseSensitive.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs index 81cf4e7a4c27e..93fd3bfca537b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/NativeFormat/NativeFormatRuntimeAssembly.cs @@ -120,7 +120,7 @@ protected sealed override IEnumerable TypeForwardInfos IEnumerable allNamespaceHandles = reader.GetTransitiveNamespaces(topLevelNamespaceHandles); foreach (NamespaceDefinitionHandle namespaceHandle in allNamespaceHandles) { - string namespaceName = null; + string? namespaceName = null; foreach (TypeForwarderHandle typeForwarderHandle in namespaceHandle.GetNamespaceDefinition(reader).TypeForwarders) { if (namespaceName == null) @@ -182,7 +182,7 @@ internal sealed override RuntimeAssemblyName RuntimeAssemblyName public sealed override bool Equals(object obj) { - NativeFormatRuntimeAssembly other = obj as NativeFormatRuntimeAssembly; + NativeFormatRuntimeAssembly? other = obj as NativeFormatRuntimeAssembly; return Equals(other); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs index 0234c88357b26..491acf920ec10 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs @@ -29,7 +29,7 @@ namespace System.Reflection.Runtime.Assemblies // internal abstract partial class RuntimeAssemblyInfo : RuntimeAssembly, IEquatable { - public bool Equals(RuntimeAssemblyInfo other) + public bool Equals(RuntimeAssemblyInfo? other) { if (other == null) return false; @@ -102,7 +102,7 @@ public sealed override Type GetType(string name, bool throwOnError, bool ignoreC } #pragma warning disable 0067 // Silence warning about ModuleResolve not being used. - public sealed override event ModuleResolveEventHandler ModuleResolve; + public sealed override event ModuleResolveEventHandler? ModuleResolve; #pragma warning restore 0067 public sealed override bool ReflectionOnly => false; // ReflectionOnly loading not supported. @@ -120,14 +120,14 @@ public sealed override AssemblyName GetName() public sealed override Type[] GetForwardedTypes() { List types = new List(); - List exceptions = null; + List? exceptions = null; foreach (TypeForwardInfo typeForwardInfo in TypeForwardInfos) { string fullTypeName = typeForwardInfo.NamespaceName.Length == 0 ? typeForwardInfo.TypeName : typeForwardInfo.NamespaceName + "." + typeForwardInfo.TypeName; RuntimeAssemblyName redirectedAssemblyName = typeForwardInfo.RedirectedAssemblyName; - Type type = null; + Type? type = null; RuntimeAssemblyInfo redirectedAssembly; Exception exception = TryGetRuntimeAssembly(redirectedAssemblyName, out redirectedAssembly); if (exception == null) @@ -252,6 +252,7 @@ private CaseSensitiveTypeCache CaseSensitiveTypeTable } } +#pragma warning disable 0672 // GlobalAssemblyCache is Obsolete. public sealed override bool GlobalAssemblyCache { get @@ -259,6 +260,7 @@ public sealed override bool GlobalAssemblyCache return false; } } +#pragma warning restore 0672 public sealed override long HostContext { @@ -274,8 +276,6 @@ public sealed override Module LoadModule(string moduleName, byte[] rawModule, by throw new PlatformNotSupportedException(); } - internal const string ThrowingMessageInRAF = "This member throws an exception for assemblies embedded in a single-file app"; - [RequiresAssemblyFiles(ThrowingMessageInRAF)] public sealed override FileStream GetFile(string name) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs index 368105aa0de8a..ee55cf1087d2b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs @@ -20,7 +20,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo return typeInfo.DeclaredConstructors; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { Debug.Assert(reflectedType.Equals(type)); // Constructor queries are always performed as if BindingFlags.DeclaredOnly are set so the reflectedType should always be the declaring type. return type.CoreGetDeclaredConstructors(optionalNameFilter); @@ -43,7 +43,7 @@ public sealed override void GetMemberAttributes(ConstructorInfo member, out Meth isNewSlot = false; } - public sealed override bool ImplicitlyOverrides(ConstructorInfo baseMember, ConstructorInfo derivedMember) => false; + public sealed override bool ImplicitlyOverrides(ConstructorInfo? baseMember, ConstructorInfo? derivedMember) => false; public sealed override bool IsSuppressedByMoreDerivedMember(ConstructorInfo member, ConstructorInfo[] priorMembers, int startIndex, int endIndex) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs similarity index 68% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs index 59262a3315552..e8ba0e22ea9ae 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs @@ -20,7 +20,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeIn return typeInfo.DeclaredEvents; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredEvents(optionalNameFilter, reflectedType); } @@ -29,7 +29,20 @@ public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeType public sealed override void GetMemberAttributes(EventInfo member, out MethodAttributes visibility, out bool isStatic, out bool isVirtual, out bool isNewSlot) { - MethodInfo accessorMethod = GetAccessorMethod(member); + MethodInfo? accessorMethod = GetAccessorMethod(member); + if (accessorMethod == null) + { + // If we got here, this is a inherited EventInfo that only had private accessors and is now refusing to give them out + // because that's what the rules of inherited EventInfo's are. Such a EventInfo is also considered private and will never be + // given out of a Type.GetProperty() call. So all we have to do is set its visibility to Private and it will get filtered out. + // Other values need to be set to satisfy C# but they are meaningless. + visibility = MethodAttributes.Private; + isStatic = false; + isVirtual = false; + isNewSlot = true; + return; + } + MethodAttributes methodAttributes = accessorMethod.Attributes; visibility = methodAttributes & MethodAttributes.MemberAccessMask; isStatic = (0 != (methodAttributes & MethodAttributes.Static)); @@ -50,10 +63,10 @@ public sealed override bool IsSuppressedByMoreDerivedMember(EventInfo member, Ev return false; } - public sealed override bool ImplicitlyOverrides(EventInfo baseMember, EventInfo derivedMember) + public sealed override bool ImplicitlyOverrides(EventInfo? baseMember, EventInfo? derivedMember) { - MethodInfo baseAccessor = GetAccessorMethod(baseMember); - MethodInfo derivedAccessor = GetAccessorMethod(derivedMember); + MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); + MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); return MemberPolicies.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor); } @@ -62,10 +75,9 @@ public sealed override bool OkToIgnoreAmbiguity(EventInfo m1, EventInfo m2) return false; } - private static MethodInfo GetAccessorMethod(EventInfo e) + private static MethodInfo? GetAccessorMethod(EventInfo e) { - MethodInfo accessor = e.AddMethod; - return accessor; + return e.AddMethod; } } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs index d17a43ce09252..a1fe8f0c069e7 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs @@ -20,7 +20,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeIn return typeInfo.DeclaredFields; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredFields(optionalNameFilter, reflectedType); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs index cbb620e5be3c3..50a665e5aea3a 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs @@ -28,7 +28,7 @@ internal abstract class MemberPolicies where M : MemberInfo // Returns all of the directly declared members on the given TypeInfo whose name matches optionalNameFilter. If optionalNameFilter is null, // returns all directly declared members. // - public abstract IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType); + public abstract IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType); // // Policy to decide whether a member is considered "virtual", "virtual new" and what its member visibility is. diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MemberTypeIndex.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberTypeIndex.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MemberTypeIndex.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberTypeIndex.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs similarity index 93% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs index a88d9b76b1cee..040034cb4e5e3 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs @@ -20,7 +20,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeI return typeInfo.DeclaredMethods; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredMethods(optionalNameFilter, reflectedType); } @@ -36,10 +36,10 @@ public sealed override void GetMemberAttributes(MethodInfo member, out MethodAtt isNewSlot = (0 != (methodAttributes & MethodAttributes.NewSlot)); } - public sealed override bool ImplicitlyOverrides(MethodInfo baseMember, MethodInfo derivedMember) + public sealed override bool ImplicitlyOverrides(MethodInfo? baseMember, MethodInfo? derivedMember) { // TODO (https://github.com/dotnet/corert/issues/1896) Comparing signatures is fragile. The runtime and/or toolchain should have a way of sharing this info. - return AreNamesAndSignaturesEqual(baseMember, derivedMember); + return AreNamesAndSignaturesEqual(baseMember!, derivedMember!); } // diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.NativeFormat.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.NativeFormat.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NameFilter.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs index d22d42ac12e30..9fd791d0d655b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs @@ -30,7 +30,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo typeInfo) return typeInfo.DeclaredNestedTypes; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { Debug.Assert(reflectedType.Equals(type)); // NestedType queries are always performed as if BindingFlags.DeclaredOnly are set so the reflectedType should always be the declaring type. return type.CoreGetDeclaredNestedTypes(optionalNameFilter); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs similarity index 86% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs index ee162bdfe9898..c7752043c63b9 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs @@ -20,7 +20,7 @@ public sealed override IEnumerable GetDeclaredMembers(TypeInfo typ return typeInfo.DeclaredProperties; } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) + public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredProperties(optionalNameFilter, reflectedType); } @@ -29,7 +29,7 @@ public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeT public sealed override void GetMemberAttributes(PropertyInfo member, out MethodAttributes visibility, out bool isStatic, out bool isVirtual, out bool isNewSlot) { - MethodInfo accessorMethod = GetAccessorMethod(member); + MethodInfo? accessorMethod = GetAccessorMethod(member); if (accessorMethod == null) { // If we got here, this is a inherited PropertyInfo that only had private accessors and is now refusing to give them out @@ -50,10 +50,10 @@ public sealed override void GetMemberAttributes(PropertyInfo member, out MethodA isNewSlot = (0 != (methodAttributes & MethodAttributes.NewSlot)); } - public sealed override bool ImplicitlyOverrides(PropertyInfo baseMember, PropertyInfo derivedMember) + public sealed override bool ImplicitlyOverrides(PropertyInfo? baseMember, PropertyInfo? derivedMember) { - MethodInfo baseAccessor = GetAccessorMethod(baseMember); - MethodInfo derivedAccessor = GetAccessorMethod(derivedMember); + MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); + MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); return MemberPolicies.Default.ImplicitlyOverrides(baseAccessor, derivedAccessor); } @@ -63,11 +63,11 @@ public sealed override bool ImplicitlyOverrides(PropertyInfo baseMember, Propert // public sealed override bool IsSuppressedByMoreDerivedMember(PropertyInfo member, PropertyInfo[] priorMembers, int startIndex, int endIndex) { - MethodInfo baseAccessor = GetAccessorMethod(member); + MethodInfo? baseAccessor = GetAccessorMethod(member); for (int i = startIndex; i < endIndex; i++) { PropertyInfo prior = priorMembers[i]; - MethodInfo derivedAccessor = GetAccessorMethod(prior); + MethodInfo? derivedAccessor = GetAccessorMethod(prior); if (!AreNamesAndSignaturesEqual(baseAccessor, derivedAccessor)) continue; if (derivedAccessor.IsStatic != baseAccessor.IsStatic) @@ -85,9 +85,9 @@ public sealed override bool OkToIgnoreAmbiguity(PropertyInfo m1, PropertyInfo m2 return false; } - private static MethodInfo GetAccessorMethod(PropertyInfo property) + private static MethodInfo? GetAccessorMethod(PropertyInfo property) { - MethodInfo accessor = property.GetMethod; + MethodInfo? accessor = property.GetMethod; if (accessor == null) { accessor = property.SetMethod; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs index d1ce2475ea8fd..427d00b8d506b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueriedMemberList.cs @@ -105,7 +105,7 @@ public static QueriedMemberList Create(RuntimeTypeInfo type, string optionalN MemberPolicies policies = MemberPolicies.Default; - NameFilter nameFilter; + NameFilter? nameFilter; if (optionalNameFilter == null) nameFilter = null; else if (ignoreCase) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.Enumerator.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.Enumerator.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.Enumerator.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.Enumerator.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs index 1674efe1ea57a..4aadb1864c200 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/QueryResult.cs @@ -92,14 +92,14 @@ public void CopyTo(MemberInfo[] array, int startIndex) /// /// Returns a single member, null or throws AmbigousMatchException, for the Type.Get*(string name,...) family of apis. /// - public M Disambiguate() + public M? Disambiguate() { if (_queriedMembers == null) return null; // This is an uninitialized QueryResult, which is supported and represents a 0-length list of matches. int unfilteredCount = UnfilteredCount; - M match = null; + M? match = null; for (int i = 0; i < unfilteredCount; i++) { if (_queriedMembers.Matches(i, _bindingAttr)) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs index 4f20819d1d210..8d68023a81653 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs @@ -20,7 +20,7 @@ internal static class Shared // // Candidates must pass this screen before we involve the binder. // - public static bool QualifiesBasedOnParameterCount(this MethodBase methodBase, BindingFlags bindingFlags, CallingConventions callConv, Type[] argumentTypes) + public static bool QualifiesBasedOnParameterCount(this MethodBase methodBase, BindingFlags bindingFlags, CallingConventions callConv, Type?[] argumentTypes) { Debug.Assert(methodBase is not null); Debug.Assert(argumentTypes is not null); @@ -160,7 +160,7 @@ public static M GetImplicitlyOverriddenBaseClassMember(this M member) where M TypeInfo typeInfo = member.DeclaringType.GetTypeInfo(); for (;;) { - Type baseType = typeInfo.BaseType; + Type? baseType = typeInfo.BaseType; if (baseType == null) { return null; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs index 20a2d5ff1e3d4..f564f311cc745 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/NativeFormat/NativeFormatCustomAttributeData.cs @@ -127,16 +127,16 @@ internal sealed override IList GetConstructorArgum foreach (Handle fixedArgumentHandle in _customAttribute.FixedArguments) { Handle typeHandle = ctorTypeHandles[index]; - Exception exception = null; - RuntimeTypeInfo argumentType = typeHandle.TryResolve(_reader, new TypeContext(null, null), ref exception); + Exception? exception = null; + RuntimeTypeInfo? argumentType = typeHandle.TryResolve(_reader, new TypeContext(null, null), ref exception); if (argumentType == null) { if (throwIfMissingMetadata) - throw exception; + throw exception!; return null; } - Exception e = fixedArgumentHandle.TryParseConstantValue(_reader, out object value); + Exception e = fixedArgumentHandle.TryParseConstantValue(_reader, out object? value); CustomAttributeTypedArgument customAttributeTypedArgument; if (e != null) { @@ -169,17 +169,17 @@ internal sealed override IList GetNamedArguments(b string memberName = namedArgument.Name.GetString(_reader); bool isField = (namedArgument.Flags == NamedArgumentMemberKind.Field); - Exception exception = null; - RuntimeTypeInfo argumentType = namedArgument.Type.TryResolve(_reader, new TypeContext(null, null), ref exception); + Exception? exception = null; + RuntimeTypeInfo? argumentType = namedArgument.Type.TryResolve(_reader, new TypeContext(null, null), ref exception); if (argumentType == null) { if (throwIfMissingMetadata) - throw exception; + throw exception!; else return null; } - object value; + object? value; Exception e = namedArgument.Value.TryParseConstantValue(_reader, out value); if (e != null) { @@ -199,7 +199,7 @@ internal sealed override IList GetNamedArguments(b Justification = "Metadata generation ensures fields/properties referenced from attributes are preserved.")] private static CustomAttributeNamedArgument CreateCustomAttributeNamedArgument(Type attributeType, string memberName, bool isField, CustomAttributeTypedArgument typedValue) { - MemberInfo memberInfo; + MemberInfo? memberInfo; if (isField) memberInfo = attributeType.GetField(memberName, BindingFlags.Public | BindingFlags.Instance); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs index 867a447c8c049..2b964c6b0b560 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs @@ -116,7 +116,7 @@ private static string ComputeTypedArgumentString(CustomAttributeTypedArgument ca if (argumentType == null) return cat.ToString(); - object value = cat.Value; + object? value = cat.Value; if (argumentType.IsEnum) return string.Format(typed ? "{0}" : "({1}){0}", value, argumentType.FullName); @@ -134,9 +134,9 @@ private static string ComputeTypedArgumentString(CustomAttributeTypedArgument ca else if (argumentType.IsArray) { - IList array = value as IList; + IList array = (IList)value; - Type elementType = argumentType.GetElementType(); + Type elementType = argumentType.GetElementType()!; string result = string.Format(@"new {0}[{1}] {{ ", elementType.IsEnum ? elementType.FullName : elementType.Name, array.Count); for (int i = 0; i < array.Count; i++) @@ -161,7 +161,7 @@ private string LastResortToString // Wrap a custom attribute argument (or an element of an array-typed custom attribute argument) in a CustomAttributeTypeArgument structure // for insertion into a CustomAttributeData value. // - protected CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument(object value, Type argumentType) + protected CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument(object? value, Type argumentType) { if (argumentType == typeof(object)) { @@ -179,7 +179,7 @@ protected CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument(object { if (!argumentType.IsArray) throw new BadImageFormatException(); - Type reportedElementType = argumentType.GetElementType(); + Type reportedElementType = argumentType.GetElementType()!; LowLevelListWithIList elementTypedArguments = new LowLevelListWithIList(); foreach (object elementValue in enumerableValue) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/Dispenser.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/Dispenser.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/Dispenser.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/Dispenser.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs index 40ad5cc3cf3c6..83835e4ce9e1b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs @@ -21,7 +21,7 @@ using Internal.Reflection.Core; using Internal.Reflection.Core.Execution; -using Internal.Runtime.TypeLoader; +using Internal.Runtime.Augments; namespace System.Reflection.Runtime.FieldInfos.NativeFormat { @@ -134,13 +134,13 @@ public sealed override RuntimeFieldHandle FieldHandle { get { - return TypeLoaderEnvironment.Instance.GetRuntimeFieldHandleForComponents( + return RuntimeAugments.TypeLoaderCallbacks.GetRuntimeFieldHandleForComponents( DeclaringType.TypeHandle, Name); } } - protected sealed override bool GetDefaultValueIfAvailable(bool raw, out object defaultValue) + protected sealed override bool GetDefaultValueIfAvailable(bool raw, out object? defaultValue) { return DefaultValueParser.GetDefaultValueIfAny(_reader, _field.DefaultValue, FieldType, CustomAttributes, raw, out defaultValue); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Assignability.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Assignability.cs index 074b49aab2e93..61f1bb5430c53 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Assignability.cs @@ -53,7 +53,7 @@ public static bool IsAssignableFrom(Type toTypeInfo, Type fromTypeInfo) // Desktop compat: IsAssignableFrom() considers T as assignable to Nullable (but does not check if T is a generic parameter.) if (!fromTypeInfo.IsGenericParameter) { - Type nullableUnderlyingType = Nullable.GetUnderlyingType(toTypeInfo); + Type? nullableUnderlyingType = Nullable.GetUnderlyingType(toTypeInfo); if (nullableUnderlyingType != null && nullableUnderlyingType.Equals(fromTypeInfo)) return true; } @@ -93,8 +93,8 @@ private static bool CanCastTo(this Type fromTypeInfo, Type toTypeInfo) } } - Type toElementTypeInfo = toTypeInfo.GetElementType(); - Type fromElementTypeInfo = fromTypeInfo.GetElementType(); + Type toElementTypeInfo = toTypeInfo.GetElementType()!; + Type fromElementTypeInfo = fromTypeInfo.GetElementType()!; return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo); } @@ -103,8 +103,8 @@ private static bool CanCastTo(this Type fromTypeInfo, Type toTypeInfo) if (!toTypeInfo.IsByRef) return false; - Type toElementTypeInfo = toTypeInfo.GetElementType(); - Type fromElementTypeInfo = fromTypeInfo.GetElementType(); + Type toElementTypeInfo = toTypeInfo.GetElementType()!; + Type fromElementTypeInfo = fromTypeInfo.GetElementType()!; return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo); } @@ -113,8 +113,8 @@ private static bool CanCastTo(this Type fromTypeInfo, Type toTypeInfo) if (!toTypeInfo.IsPointer) return false; - Type toElementTypeInfo = toTypeInfo.GetElementType(); - Type fromElementTypeInfo = fromTypeInfo.GetElementType(); + Type toElementTypeInfo = toTypeInfo.GetElementType()!; + Type fromElementTypeInfo = fromTypeInfo.GetElementType()!; return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo); } @@ -169,7 +169,7 @@ private static bool CanCastTo(this Type fromTypeInfo, Type toTypeInfo) Type walk = fromTypeInfo; for (;;) { - Type baseType = walk.BaseType; + Type? baseType = walk.BaseType; if (baseType == null) return false; walk = baseType; @@ -358,7 +358,7 @@ private static bool CanCastArrayToInterface(this Type fromTypeInfo, Type toTypeI Type toElementTypeInfo = toTypeGenericTypeArguments[0]; Type toTypeGenericTypeDefinition = toTypeInfo.GetGenericTypeDefinition(); - Type fromElementTypeInfo = fromTypeInfo.GetElementType(); + Type fromElementTypeInfo = fromTypeInfo.GetElementType()!; foreach (Type ifc in fromTypeInfo.GetInterfaces()) { if (ifc.IsConstructedGenericType) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/BlockedRuntimeTypeNameGenerator.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/BlockedRuntimeTypeNameGenerator.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/BlockedRuntimeTypeNameGenerator.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/BlockedRuntimeTypeNameGenerator.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs index 26d2e4bc6b090..93233d1c59a56 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.NativeFormat.cs @@ -32,7 +32,7 @@ namespace System.Reflection.Runtime.Assemblies //----------------------------------------------------------------------------------------------------------- internal partial class RuntimeAssemblyInfo { - static partial void GetNativeFormatRuntimeAssembly(AssemblyBindResult bindResult, ref RuntimeAssembly runtimeAssembly) + static partial void GetNativeFormatRuntimeAssembly(AssemblyBindResult bindResult, ref RuntimeAssembly? runtimeAssembly) { if (bindResult.Reader != null) runtimeAssembly = NativeFormatRuntimeAssembly.GetRuntimeAssembly(bindResult.Reader, bindResult.ScopeDefinitionHandle, bindResult.OverflowScopes); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.cs index e524aa3bb8b85..730215bdbab6a 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Dispensers.cs @@ -117,7 +117,7 @@ internal static Exception TryGetRuntimeAssembly(RuntimeAssemblyName assemblyRefN private static RuntimeAssembly GetRuntimeAssembly(AssemblyBindResult bindResult, string assemblyPath = null) { - RuntimeAssembly result = null; + RuntimeAssembly? result = null; GetNativeFormatRuntimeAssembly(bindResult, ref result); if (result != null) @@ -131,8 +131,8 @@ private static RuntimeAssembly GetRuntimeAssembly(AssemblyBindResult bindResult, } // Use C# partial method feature to avoid complex #if logic, whichever code files are included will drive behavior - static partial void GetNativeFormatRuntimeAssembly(AssemblyBindResult bindResult, ref RuntimeAssembly runtimeAssembly); - static partial void GetEcmaRuntimeAssembly(AssemblyBindResult bindResult, string assemblyPath, ref RuntimeAssembly runtimeAssembly); + static partial void GetNativeFormatRuntimeAssembly(AssemblyBindResult bindResult, ref RuntimeAssembly? runtimeAssembly); + static partial void GetEcmaRuntimeAssembly(AssemblyBindResult bindResult, string assemblyPath, ref RuntimeAssembly? runtimeAssembly); } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.NativeFormat.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.NativeFormat.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs index 2541bc6050666..51847c8e868c3 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Helpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs @@ -78,7 +78,7 @@ public static RuntimeNamedTypeInfo CastToRuntimeNamedTypeInfo(this Type type) public static RuntimeTypeInfo CastToRuntimeTypeInfo(this Type type) { Debug.Assert(type == null || type is RuntimeTypeInfo); - return (RuntimeTypeInfo)type; + return (RuntimeTypeInfo)type!; } public static ReadOnlyCollection ToReadOnlyCollection(this IEnumerable enumeration) @@ -161,16 +161,12 @@ public static RuntimeMethodInfo GetInvokeMethod(this RuntimeTypeInfo delegateTyp { Debug.Assert(delegateType.IsDelegate); - MethodInfo invokeMethod = delegateType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + MethodInfo? invokeMethod = delegateType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (invokeMethod == null) { // No Invoke method found. Since delegate types are compiler constructed, the most likely cause is missing metadata rather than // a missing Invoke method. - - // We're deliberating calling FullName rather than ToString() because if it's the type that's missing metadata, - // the FullName property constructs a more informative MissingMetadataException than we can. - string fullName = delegateType.FullName; - throw new MissingMetadataException(SR.Format(SR.Arg_InvokeMethodMissingMetadata, fullName)); // No invoke method found. + throw ReflectionCoreExecution.ExecutionDomain.CreateMissingMetadataException(delegateType); } return (RuntimeMethodInfo)invokeMethod; } @@ -207,7 +203,7 @@ public static object[] InstantiateAsArray(this IEnumerable return result; } - public static bool GetCustomAttributeDefaultValueIfAny(IEnumerable customAttributes, bool raw, out object defaultValue) + public static bool GetCustomAttributeDefaultValueIfAny(IEnumerable customAttributes, bool raw, out object? defaultValue) { // Legacy: If there are multiple default value attribute, the desktop picks one at random (and so do we...) foreach (CustomAttributeData cad in customAttributes) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ListBuilder.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ListBuilder.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ListBuilder.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ListBuilder.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs index 1c9480246005d..3a1244dee6233 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs @@ -9,6 +9,7 @@ using System.Collections; using System.Collections.Generic; using System.Reflection.Runtime.Assemblies; +using System.Runtime.CompilerServices; using Internal.LowLevelLinq; using Internal.Reflection.Core; @@ -23,6 +24,8 @@ namespace System.Reflection.Runtime.General // // Collect various metadata reading tasks for better chunking... // + [ReflectionBlocked] + [CLSCompliant(false)] public static class NativeFormatMetadataReaderExtensions { public static bool StringOrNullEquals(this ConstantStringValueHandle handle, string valueOrNull, MetadataReader reader) @@ -221,8 +224,8 @@ private static Exception ParseBoxedEnumConstantValue(this ConstantBoxedEnumValue { ConstantBoxedEnumValue record = handle.GetConstantBoxedEnumValue(reader); - Exception exception = null; - Type enumType = record.Type.TryResolve(reader, new TypeContext(null, null), ref exception); + Exception? exception = null; + Type? enumType = record.Type.TryResolve(reader, new TypeContext(null, null), ref exception); if (enumType == null) { value = null; @@ -317,9 +320,9 @@ private static Exception ParseBoxedEnumConstantValue(this ConstantBoxedEnumValue } } - public static object ParseConstantValue(this Handle handle, MetadataReader reader) + public static object? ParseConstantValue(this Handle handle, MetadataReader reader) { - object value; + object? value; Exception exception = handle.TryParseConstantValue(reader, out value); if (exception != null) throw exception; @@ -359,7 +362,7 @@ public static object ParseConstantNumericValue(this Handle handle, MetadataReade } } - public static Exception TryParseConstantValue(this Handle handle, MetadataReader reader, out object value) + public static Exception TryParseConstantValue(this Handle handle, MetadataReader reader, out object? value) { HandleType handleType = handle.HandleType; switch (handleType) @@ -385,8 +388,8 @@ public static Exception TryParseConstantValue(this Handle handle, MetadataReader case HandleType.TypeReference: case HandleType.TypeSpecification: { - Exception exception = null; - Type type = handle.TryResolve(reader, new TypeContext(null, null), ref exception); + Exception? exception = null; + Type? type = handle.TryResolve(reader, new TypeContext(null, null), ref exception); value = type; return (value == null) ? exception : null; } @@ -399,7 +402,7 @@ public static Exception TryParseConstantValue(this Handle handle, MetadataReader } default: { - Exception exception; + Exception? exception; value = handle.TryParseConstantArray(reader, out exception); if (value == null) return exception; @@ -408,7 +411,7 @@ public static Exception TryParseConstantValue(this Handle handle, MetadataReader } } - private static Array TryParseConstantArray(this Handle handle, MetadataReader reader, out Exception exception) + private static Array TryParseConstantArray(this Handle handle, MetadataReader reader, out Exception? exception) { exception = null; @@ -461,11 +464,11 @@ private static Array TryParseConstantArray(this Handle handle, MetadataReader re int i = 0; foreach (Handle constantHandle in constantHandles) { - object elementValue; + object? elementValue; exception = constantHandle.TryParseConstantValue(reader, out elementValue); if (exception != null) return null; - elements[i] = (string)elementValue; + elements[i] = (string)elementValue!; i++; } return elements; @@ -474,7 +477,7 @@ private static Array TryParseConstantArray(this Handle handle, MetadataReader re case HandleType.ConstantHandleArray: { HandleCollection constantHandles = handle.ToConstantHandleArrayHandle(reader).GetConstantHandleArray(reader).Value; - object[] elements = new object[constantHandles.Count]; + object?[] elements = new object[constantHandles.Count]; int i = 0; foreach (Handle constantHandle in constantHandles) { @@ -490,12 +493,12 @@ private static Array TryParseConstantArray(this Handle handle, MetadataReader re } } - private static Array TryParseConstantEnumArray(this ConstantEnumArrayHandle handle, MetadataReader reader, out Exception exception) + private static Array TryParseConstantEnumArray(this ConstantEnumArrayHandle handle, MetadataReader reader, out Exception? exception) { exception = null; ConstantEnumArray enumArray = handle.GetConstantEnumArray(reader); - Type elementType = enumArray.ElementType.TryResolve(reader, new TypeContext(null, null), ref exception); + Type? elementType = enumArray.ElementType.TryResolve(reader, new TypeContext(null, null), ref exception); if (exception != null) return null; @@ -630,7 +633,7 @@ public static string ToNamespaceName(this NamespaceDefinitionHandle namespaceDef continue; } - throw new BadImageFormatException(SR.Bif_InvalidMetadata); + throw new BadImageFormatException(); } return ns; } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/MetadataReaderExtensions.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs similarity index 96% rename from src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/MetadataReaderExtensions.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs index fa4cc68358574..35d240d925b3e 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/MetadataReaderExtensions.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs @@ -2,17 +2,20 @@ // The .NET Foundation licenses this file to you under the MIT license. -using global::System; -using global::System.Reflection; -using global::System.Collections.Generic; +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Runtime.CompilerServices; -using global::Internal.Metadata.NativeFormat; +using Internal.Metadata.NativeFormat; using Debug = System.Diagnostics.Debug; using AssemblyFlags = Internal.Metadata.NativeFormat.AssemblyFlags; namespace System.Reflection.Runtime.General { + [ReflectionBlocked] + [CLSCompliant(false)] public static partial class MetadataReaderExtensions { /// diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NamespaceChain.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NamespaceChain.cs index 34b97186d7507..dd52a03e6b5af 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NamespaceChain.cs @@ -39,7 +39,7 @@ internal NamespaceChain(MetadataReader reader, NamespaceDefinitionHandle innerMo continue; } - throw new BadImageFormatException(SR.Bif_InvalidMetadata); + throw new BadImageFormatException(); } DefiningScope = currentNamespaceHandle.ToScopeDefinitionHandle(reader); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs similarity index 93% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs index 0da7bd27a6fd2..24fd595d5bd09 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/NativeFormat/DefaultValueParser.cs @@ -8,7 +8,7 @@ namespace System.Reflection.Runtime.General.NativeFormat { internal static class DefaultValueParser { - public static bool GetDefaultValueIfAny(MetadataReader reader, Handle constantHandle, Type declaredType, IEnumerable customAttributes, bool raw, out object defaultValue) + public static bool GetDefaultValueIfAny(MetadataReader reader, Handle constantHandle, Type declaredType, IEnumerable customAttributes, bool raw, out object? defaultValue) { if (!(constantHandle.IsNull(reader))) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs index 08ad466e41a0c..087f2cfdcf087 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.NativeFormat.cs @@ -14,7 +14,6 @@ namespace System.Reflection.Runtime.General { - public partial struct QMethodDefinition { public QMethodDefinition(MetadataReader reader, MethodHandle handle) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.cs similarity index 93% rename from src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.cs index 2f47be124a0a2..f8c7e014c857e 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System/Reflection/Runtime/General/QHandles.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QHandles.cs @@ -8,12 +8,15 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using Internal.Metadata.NativeFormat; using Internal.Runtime.TypeLoader; namespace Internal.Reflection.Core { + [ReflectionBlocked] + [CLSCompliant(false)] public struct QScopeDefinition : IEquatable { public QScopeDefinition(MetadataReader reader, ScopeDefinitionHandle handle) @@ -60,6 +63,8 @@ public override int GetHashCode() namespace System.Reflection.Runtime.General { + [ReflectionBlocked] + [CLSCompliant(false)] public struct QHandle : IEquatable { public QHandle(MetadataReader reader, Handle handle) @@ -96,6 +101,8 @@ public override int GetHashCode() private readonly Handle _handle; } + [ReflectionBlocked] + [CLSCompliant(false)] public partial struct QMethodDefinition { private QMethodDefinition(object reader, int token) @@ -120,6 +127,8 @@ public static QMethodDefinition FromObjectAndInt(object reader, int token) private readonly int _handle; } + [ReflectionBlocked] + [CLSCompliant(false)] public partial struct QTypeDefinition { public object Reader { get { return _reader; } } @@ -134,6 +143,8 @@ public partial struct QTypeDefinition } + [ReflectionBlocked] + [CLSCompliant(false)] public partial struct QTypeDefRefOrSpec { public object Reader { get { return _reader; } } @@ -147,6 +158,8 @@ public partial struct QTypeDefRefOrSpec private readonly int _handle; } + [ReflectionBlocked] + [CLSCompliant(false)] public struct QGenericParameter : IEquatable { public QGenericParameter(MetadataReader reader, GenericParameterHandle handle) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QSignatureTypeHandle.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QSignatureTypeHandle.NativeFormat.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QSignatureTypeHandle.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QSignatureTypeHandle.NativeFormat.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs similarity index 87% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs index b1307eea2f27a..59925d98a73fd 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/QSignatureTypeHandle.cs @@ -9,9 +9,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Runtime.TypeInfos; +using System.Runtime.CompilerServices; namespace System.Reflection.Runtime.General { + [ReflectionBlocked] + [CLSCompliant(false)] public partial struct QSignatureTypeHandle { public object Reader { get { return _reader; } } @@ -23,14 +26,14 @@ public partial struct QSignatureTypeHandle internal RuntimeTypeInfo Resolve(TypeContext typeContext) { - Exception exception = null; - RuntimeTypeInfo runtimeType = TryResolve(typeContext, ref exception); + Exception? exception = null; + RuntimeTypeInfo? runtimeType = TryResolve(typeContext, ref exception); if (runtimeType == null) - throw exception; + throw exception!; return runtimeType; } - internal RuntimeTypeInfo TryResolve(TypeContext typeContext, ref Exception exception) + internal RuntimeTypeInfo? TryResolve(TypeContext typeContext, ref Exception? exception) { if (Reader is global::Internal.Metadata.NativeFormat.MetadataReader) { @@ -70,8 +73,8 @@ internal string FormatTypeName(TypeContext typeContext) // Though we wrap this in a try-catch as a failsafe, this code must still strive to avoid triggering MissingMetadata exceptions // (non-error exceptions are very annoying when debugging.) - Exception exception = null; - RuntimeTypeInfo runtimeType = TryResolve(typeContext, ref exception); + Exception? exception = null; + RuntimeTypeInfo? runtimeType = TryResolve(typeContext, ref exception); if (runtimeType == null) return Type.DefaultTypeNameWhenMissingMetadata; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs index 0b211124f26b8..c1321e4a4797d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs @@ -183,7 +183,7 @@ public sealed override object ActivatorCreateInstance( [DebuggerStepThrough] public sealed override object ActivatorCreateInstance( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type type, BindingFlags bindingAttr, Binder? binder, object[]? args, CultureInfo? culture, object[]? activationAttributes) + Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) { return ActivatorImplementation.CreateInstance(type, bindingAttr, binder, args, culture, activationAttributes); } @@ -323,7 +323,7 @@ private static RuntimeMethodInfo LookupMethodForCreateDelegate(RuntimeTypeInfo r while (containingType != null) { - MethodInfo methodInfo = containingType.GetMethod(method, 0, bindingFlags, null, parameterTypes, null); + MethodInfo? methodInfo = containingType.GetMethod(method, 0, bindingFlags, null, parameterTypes, null); if (methodInfo != null && methodInfo.ReturnType.Equals(invokeMethod.ReturnType)) return (RuntimeMethodInfo)methodInfo; // This cast is safe since we already verified that containingType is runtime implemented. diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeHandleKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/RuntimeTypeHandleKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeHandleKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/RuntimeTypeHandleKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ThunkedApis.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ThunkedApis.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs index 295c9f8777aa7..1eb4d3dcd69ab 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ThunkedApis.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs @@ -41,7 +41,7 @@ public sealed override Stream GetManifestResourceStream(Type type, string name) } else { - string nameSpace = type.Namespace; + string? nameSpace = type.Namespace; if (nameSpace != null) { sb.Append(nameSpace); @@ -68,8 +68,9 @@ public override string Location } } + [Obsolete("Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location.", DiagnosticId = "SYSLIB0012", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [RequiresAssemblyFiles("The code will throw for assemblies embedded in a single-file app")] - public sealed override string CodeBase + public sealed override string? CodeBase { get { @@ -175,7 +176,7 @@ public sealed override Type[] GetGenericArguments() [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2073:UnrecognizedReflectionPattern", Justification = "The returned interface is one of the interfaces implemented by this type and does have DynamicallyAccessedMemberTypes.Interfaces")] - public sealed override Type GetInterface(string name, bool ignoreCase) + public sealed override Type? GetInterface(string name, bool ignoreCase) { if (name == null) throw new ArgumentNullException("fullname" /* Yep, CoreCLR names this different than the ref assembly */); @@ -184,7 +185,7 @@ public sealed override Type GetInterface(string name, bool ignoreCase) string ns; SplitTypeName(name, out simpleName, out ns); - Type match = null; + Type? match = null; foreach (Type ifc in ImplementedInterfaces) { string ifcSimpleName = ifc.Name; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ToStringUtils.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ToStringUtils.cs index 9fe84bac777ae..0a9ff9c82f83a 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ToStringUtils.cs @@ -21,7 +21,7 @@ public static string FormatTypeName(this QTypeDefRefOrSpec qualifiedTypeHandle, // Though we wrap this in a try-catch as a failsafe, this code must still strive to avoid triggering MissingMetadata exceptions // (non-error exceptions are very annoying when debugging.) - Exception exception = null; + Exception? exception = null; RuntimeTypeInfo runtimeType = qualifiedTypeHandle.TryResolve(typeContext, ref exception); if (runtimeType == null) return Type.DefaultTypeNameWhenMissingMetadata; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeContext.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeContext.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeContext.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeContext.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeForwardInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeForwardInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeForwardInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeForwardInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs similarity index 85% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs index aa2a4ebf61618..838f6a1f6dfa1 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.NativeFormat.cs @@ -27,14 +27,14 @@ internal static partial class TypeResolver // internal static RuntimeTypeInfo Resolve(this Handle typeDefRefOrSpec, MetadataReader reader, TypeContext typeContext) { - Exception exception = null; - RuntimeTypeInfo runtimeType = typeDefRefOrSpec.TryResolve(reader, typeContext, ref exception); + Exception? exception = null; + RuntimeTypeInfo? runtimeType = typeDefRefOrSpec.TryResolve(reader, typeContext, ref exception); if (runtimeType == null) - throw exception; + throw exception!; return runtimeType; } - internal static RuntimeTypeInfo TryResolve(this Handle typeDefRefOrSpec, MetadataReader reader, TypeContext typeContext, ref Exception exception) + internal static RuntimeTypeInfo? TryResolve(this Handle typeDefRefOrSpec, MetadataReader reader, TypeContext typeContext, ref Exception? exception) { HandleType handleType = typeDefRefOrSpec.HandleType; if (handleType == HandleType.TypeDefinition) @@ -64,7 +64,7 @@ internal static RuntimeTypeInfo ResolveTypeDefinition(this TypeDefinitionHandle // // Main routine to parse a metadata type specification signature. // - private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHandle typeSpecHandle, MetadataReader reader, TypeContext typeContext, ref Exception exception) + private static RuntimeTypeInfo? TryResolveTypeSignature(this TypeSpecificationHandle typeSpecHandle, MetadataReader reader, TypeContext typeContext, ref Exception? exception) { Handle typeHandle = typeSpecHandle.GetTypeSpecification(reader).Signature; switch (typeHandle.HandleType) @@ -75,7 +75,7 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan int rank = sig.Rank; if (rank <= 0) throw new BadImageFormatException(); // Bad rank. - RuntimeTypeInfo elementType = sig.ElementType.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? elementType = sig.ElementType.TryResolve(reader, typeContext, ref exception); if (elementType == null) return null; return elementType.GetMultiDimArrayType(rank); @@ -84,7 +84,7 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan case HandleType.ByReferenceSignature: { ByReferenceSignature sig = typeHandle.ToByReferenceSignatureHandle(reader).GetByReferenceSignature(reader); - RuntimeTypeInfo targetType = sig.Type.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? targetType = sig.Type.TryResolve(reader, typeContext, ref exception); if (targetType == null) return null; return targetType.GetByRefType(); @@ -99,7 +99,7 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan case HandleType.PointerSignature: { PointerSignature sig = typeHandle.ToPointerSignatureHandle(reader).GetPointerSignature(reader); - RuntimeTypeInfo targetType = sig.Type.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? targetType = sig.Type.TryResolve(reader, typeContext, ref exception); if (targetType == null) return null; return targetType.GetPointerType(); @@ -108,7 +108,7 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan case HandleType.SZArraySignature: { SZArraySignature sig = typeHandle.ToSZArraySignatureHandle(reader).GetSZArraySignature(reader); - RuntimeTypeInfo elementType = sig.ElementType.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? elementType = sig.ElementType.TryResolve(reader, typeContext, ref exception); if (elementType == null) return null; return elementType.GetArrayType(); @@ -122,13 +122,13 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan case HandleType.TypeInstantiationSignature: { TypeInstantiationSignature sig = typeHandle.ToTypeInstantiationSignatureHandle(reader).GetTypeInstantiationSignature(reader); - RuntimeTypeInfo genericTypeDefinition = sig.GenericType.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? genericTypeDefinition = sig.GenericType.TryResolve(reader, typeContext, ref exception); if (genericTypeDefinition == null) return null; LowLevelList genericTypeArguments = new LowLevelList(); foreach (Handle genericTypeArgumentHandle in sig.GenericTypeArguments) { - RuntimeTypeInfo genericTypeArgument = genericTypeArgumentHandle.TryResolve(reader, typeContext, ref exception); + RuntimeTypeInfo? genericTypeArgument = genericTypeArgumentHandle.TryResolve(reader, typeContext, ref exception); if (genericTypeArgument == null) return null; genericTypeArguments.Add(genericTypeArgument); @@ -157,7 +157,7 @@ private static RuntimeTypeInfo TryResolveTypeSignature(this TypeSpecificationHan // [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "Resolves type references within metadata. We ensure metadata is consistent.")] - private static RuntimeTypeInfo TryResolveTypeReference(this TypeReferenceHandle typeReferenceHandle, MetadataReader reader, ref Exception exception) + private static RuntimeTypeInfo? TryResolveTypeReference(this TypeReferenceHandle typeReferenceHandle, MetadataReader reader, ref Exception? exception) { RuntimeTypeHandle resolvedRuntimeTypeHandle; if (ReflectionCoreExecution.ExecutionEnvironment.TryGetNamedTypeForTypeReference(reader, typeReferenceHandle, out resolvedRuntimeTypeHandle)) @@ -167,7 +167,7 @@ private static RuntimeTypeInfo TryResolveTypeReference(this TypeReferenceHandle string name = typeReference.TypeName.GetString(reader); Handle parent = typeReference.ParentNamespaceOrType; HandleType parentType = parent.HandleType; - TypeInfo outerTypeInfo = null; + TypeInfo? outerTypeInfo = null; // Check if this is a reference to a nested type. @@ -177,7 +177,7 @@ private static RuntimeTypeInfo TryResolveTypeReference(this TypeReferenceHandle } else if (parentType == HandleType.TypeReference) { - RuntimeTypeInfo outerType = parent.ToTypeReferenceHandle(reader).TryResolveTypeReference(reader, ref exception); + RuntimeTypeInfo? outerType = parent.ToTypeReferenceHandle(reader).TryResolveTypeReference(reader, ref exception); if (outerType == null) return null; outerTypeInfo = outerType; // Since we got to outerType via a metadata reference, we're assured GetTypeInfo() won't throw a MissingMetadataException. @@ -185,7 +185,7 @@ private static RuntimeTypeInfo TryResolveTypeReference(this TypeReferenceHandle if (outerTypeInfo != null) { // It was a nested type. We've already resolved the containing type recursively - just find the nested among its direct children. - TypeInfo resolvedTypeInfo = outerTypeInfo.GetDeclaredNestedType(name); + TypeInfo? resolvedTypeInfo = outerTypeInfo.GetDeclaredNestedType(name); if (resolvedTypeInfo == null) { exception = ReflectionCoreExecution.ExecutionDomain.CreateMissingMetadataException(outerTypeInfo, name); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.cs index fcf6e8d4470b0..f4665d0866567 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeResolver.cs @@ -24,14 +24,14 @@ internal static partial class TypeResolver // internal static RuntimeTypeInfo Resolve(this QTypeDefRefOrSpec typeDefOrRefOrSpec, TypeContext typeContext) { - Exception exception = null; + Exception? exception = null; RuntimeTypeInfo runtimeType = typeDefOrRefOrSpec.TryResolve(typeContext, ref exception); if (runtimeType == null) - throw exception; + throw exception!; return runtimeType; } - internal static RuntimeTypeInfo TryResolve(this QTypeDefRefOrSpec typeDefOrRefOrSpec, TypeContext typeContext, ref Exception exception) + internal static RuntimeTypeInfo TryResolve(this QTypeDefRefOrSpec typeDefOrRefOrSpec, TypeContext typeContext, ref Exception? exception) { if (typeDefOrRefOrSpec.IsNativeFormatMetadataBased) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.NativeFormat.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs index e9f8abb56ebfe..cdc37f01a1b53 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeUnifier.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/TypeUnifier.cs @@ -117,7 +117,7 @@ private static RuntimeConstructedGenericTypeInfo WithVerifiedTypeHandle(this Run public static RuntimeTypeInfo GetTypeForRuntimeTypeHandle(this RuntimeTypeHandle typeHandle) { - Type type = Type.GetTypeFromHandle(typeHandle); + Type type = Type.GetTypeFromHandle(typeHandle)!; return type.CastToRuntimeTypeInfo(); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs index 9a00c6995cbe3..3ae697e0b84ad 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvoker.cs @@ -21,7 +21,7 @@ public CustomMethodInvoker(Type thisType, Type[] parameterTypes, InvokerOptions _parameterTypes = parameterTypes; } - protected sealed override object Invoke(object thisObject, object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException) + protected sealed override object? Invoke(object? thisObject, object?[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException) { Debug.Assert(arguments != null); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodInvokerAction.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs index bda098b67e738..2b3c78ff34270 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.Nullable.cs @@ -77,8 +77,9 @@ public static Dictionary Map map.AddMethod(type, nameof(Nullable.GetValueOrDefault), Array.Empty(), NullableGetValueOrDefault); + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements", + Justification = "Constructed MethodTable of a Nullable forces a constructed MethodTable of the element type")] static object NullableGetValueOrDefault(object thisObject, object[] args, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type thisType) { if (thisObject == null) diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.String.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs similarity index 93% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs index 5848b2ed96b47..6b81aaaeb2bf2 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/CustomMethodMapper.cs @@ -16,7 +16,7 @@ internal static partial class CustomMethodMapper // public static MethodInvoker GetCustomMethodInvokerIfNeeded(this MethodBase methodBase) { - Type declaringType = methodBase.DeclaringType; + Type declaringType = methodBase.DeclaringType!; bool isNullable = declaringType.IsConstructedGenericType && declaringType.GetGenericTypeDefinition() == typeof(Nullable<>); Dictionary map; @@ -27,7 +27,7 @@ public static MethodInvoker GetCustomMethodInvokerIfNeeded(this MethodBase metho else return null; - if (!(map.TryGetValue(methodBase.MetadataDefinitionMethod, out CustomMethodInvokerAction action))) + if (!map.TryGetValue(methodBase.MetadataDefinitionMethod, out CustomMethodInvokerAction? action)) return null; ParameterInfo[] parameterInfos = methodBase.GetParametersNoCopy(); @@ -52,7 +52,7 @@ private static void AddMethod(this Dictionary 0); - RuntimeTypeHandle[] genericArgHandles; + RuntimeTypeHandle[]? genericArgHandles; if (genericArgs != null) { genericArgHandles = new RuntimeTypeHandle[genericArgs.Length]; @@ -200,9 +200,9 @@ public RuntimeMethodHandle GetRuntimeMethodHandle(Type[] genericArgs) genericArgHandles = null; } - TypeManagerHandle typeManager = TypeLoaderEnvironment.Instance.ModuleList.GetModuleForMetadataReader(Reader); + TypeManagerHandle typeManager = RuntimeAugments.TypeLoaderCallbacks.GetModuleForMetadataReader(Reader); - return TypeLoaderEnvironment.Instance.GetRuntimeMethodHandleForComponents( + return RuntimeAugments.TypeLoaderCallbacks.GetRuntimeMethodHandleForComponents( DeclaringType.TypeHandle, Name, RuntimeSignature.CreateFromMethodHandle(typeManager, MethodHandle.AsInt()), diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs similarity index 86% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs index 945cc9e2a94d0..49e7f618c2518 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs @@ -14,7 +14,7 @@ namespace System.Reflection.Runtime.MethodInfos { internal sealed class OpenMethodInvoker : MethodInvoker { - protected sealed override object Invoke(object thisObject, object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException) + protected sealed override object? Invoke(object? thisObject, object?[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException) { throw new InvalidOperationException(SR.Arg_UnboundGenParam); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs index 7f5dde597cce8..5c5d30bbb9d43 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs @@ -27,7 +27,7 @@ private RuntimeCLSIDNullaryConstructorInfo(RuntimeCLSIDTypeInfo declaringType) public sealed override MethodAttributes Attributes => MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; public sealed override CallingConventions CallingConvention => CallingConventions.Standard | CallingConventions.HasThis; - public sealed override IEnumerable CustomAttributes => Empty.Enumerable; + public sealed override IEnumerable CustomAttributes => Array.Empty(); public sealed override Type DeclaringType => _declaringType; public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) @@ -50,7 +50,7 @@ public sealed override bool Equals(object obj) public sealed override int GetHashCode() => _declaringType.GetHashCode(); - public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, object?[]? parameters, CultureInfo culture) { throw new PlatformNotSupportedException(); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs index e46d25dd91f5d..53cf1f0f963cc 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs @@ -75,7 +75,7 @@ public sealed override int GetHashCode() return _genericMethodDefinition.GetHashCode(); } - public sealed override int GenericParameterCount => _genericMethodDefinition.GenericParameterCount; + internal sealed override int GenericParameterCount => _genericMethodDefinition.GenericParameterCount; public sealed override MethodInfo GetGenericMethodDefinition() { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs similarity index 94% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs index 708e25cc99035..3550d71105014 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs @@ -66,10 +66,10 @@ public sealed override ParameterInfo[] GetParametersNoCopy() public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); - public abstract override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture); + public abstract override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture); [DebuggerGuidedStepThrough] - public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + public sealed override object Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture) { if (parameters == null) parameters = Array.Empty(); @@ -98,9 +98,9 @@ public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder throw; } - object result = methodInvoker.Invoke(obj, parameters, binder, invokeAttr, culture); + object? result = methodInvoker.Invoke(obj, parameters, binder, invokeAttr, culture); System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); - return result; + return result!; } public abstract override MethodBase MetadataDefinitionMethod { get; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs index 9220b3a0bb6eb..409186ad65429 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs @@ -31,7 +31,7 @@ private RuntimeDummyMethodInfo() { } public sealed override bool IsConstructedGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethodDefinition { get { throw NotImplemented.ByDesign; } } - public sealed override int GenericParameterCount { get { throw NotImplemented.ByDesign; } } + internal sealed override int GenericParameterCount { get { throw NotImplemented.ByDesign; } } public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) { throw NotImplemented.ByDesign; } public sealed override MethodImplAttributes MethodImplementationFlags { get { throw NotImplemented.ByDesign; } } public sealed override Module Module { get { throw NotImplemented.ByDesign; } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs index 2f17ba860e949..4892116492429 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodHelpers.cs @@ -105,7 +105,7 @@ internal static string ComputeToString(MethodBase contextMethod, RuntimeTypeInfo { sb.Append(sep); sep = ","; - string name = methodTypeArgument.InternalNameIfAvailable; + string? name = methodTypeArgument.InternalNameIfAvailable; if (name == null) name = Type.DefaultTypeNameWhenMissingMetadata; sb.Append(methodTypeArgument.Name); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index 3d9fc962699bf..e9907db30eb9c 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -132,7 +132,7 @@ public sealed override Type[] GetGenericArguments() return RuntimeGenericArgumentsOrParameters.CloneTypeArray(); } - public abstract override int GenericParameterCount { get; } + internal abstract override int GenericParameterCount { get; } public abstract override MethodInfo GetGenericMethodDefinition(); @@ -161,12 +161,12 @@ public sealed override ParameterInfo[] GetParametersNoCopy() public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); [DebuggerGuidedStepThroughAttribute] - public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + public sealed override object? Invoke(object? obj, BindingFlags invokeAttr, Binder binder, object?[]? parameters, CultureInfo culture) { if (parameters == null) parameters = Array.Empty(); MethodInvoker methodInvoker = this.MethodInvoker; - object result = methodInvoker.Invoke(obj, parameters, binder, invokeAttr, culture); + object? result = methodInvoker.Invoke(obj, parameters, binder, invokeAttr, culture); System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return result; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs index 252c556e21d24..c75d371be48d7 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs @@ -117,7 +117,7 @@ public sealed override bool IsGenericMethodDefinition } } - public sealed override int GenericParameterCount => _common.GenericParameterCount; + internal sealed override int GenericParameterCount => _common.GenericParameterCount; [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")] [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] @@ -135,7 +135,7 @@ public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) throw new ArgumentNullException(); if (typeArgument is not RuntimeType) - throw new ArgumentException(SR.Format(SR.Reflection_CustomReflectionObjectsNotSupported, typeArguments[i]), "typeArguments[" + i + "]"); // Not a runtime type. + throw new PlatformNotSupportedException(SR.Format(SR.Reflection_CustomReflectionObjectsNotSupported, typeArguments[i])); if (typeArgument.IsByRefLike) throw new BadImageFormatException(SR.CannotUseByRefLikeTypeInInstantiation); @@ -318,7 +318,7 @@ internal sealed override MethodInvoker GetUncachedMethodInvoker(RuntimeTypeInfo[ static Type Unwrap(Type t) { while (t.HasElementType) - t = t.GetElementType(); + t = t.GetElementType()!; return t; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs index 030759f35f5a2..acd2980e29194 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs @@ -76,7 +76,7 @@ public sealed override Type DeclaringType } [DebuggerGuidedStepThrough] - public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + public sealed override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture) { if (parameters == null) parameters = Array.Empty(); @@ -86,9 +86,9 @@ public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, obj // Reflection.Core does not hardcode these special cases. It's up to the ExecutionEnvironment to steer // us the right way by coordinating the implementation of NewObject and MethodInvoker. object newObject = ReflectionCoreExecution.ExecutionEnvironment.NewObject(this.DeclaringType.TypeHandle); - object ctorAllocatedObject = this.MethodInvoker.Invoke(newObject, parameters, binder, invokeAttr, culture); + object ctorAllocatedObject = this.MethodInvoker.Invoke(newObject, parameters, binder, invokeAttr, culture)!; System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); - return newObject != null ? newObject : ctorAllocatedObject; + return newObject ?? ctorAllocatedObject; } public sealed override MethodBase MetadataDefinitionMethod diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs index f6129972b3169..939535180b69e 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs @@ -48,7 +48,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -77,12 +77,12 @@ public sealed override int MetadataToken } [DebuggerGuidedStepThrough] - public sealed override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) + public sealed override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture) { if (parameters == null) parameters = Array.Empty(); - object ctorAllocatedObject = this.MethodInvoker.Invoke(null, parameters, binder, invokeAttr, culture); + object ctorAllocatedObject = this.MethodInvoker.Invoke(null, parameters, binder, invokeAttr, culture)!; System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return ctorAllocatedObject; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs index 4d432d988244f..8a03a7a2f3192 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs @@ -50,7 +50,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -108,7 +108,7 @@ public sealed override bool IsGenericMethodDefinition } } - public sealed override int GenericParameterCount => 0; + internal sealed override int GenericParameterCount => 0; [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")] [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/VirtualRuntimeParameterInfoArray.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/VirtualRuntimeParameterInfoArray.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/VirtualRuntimeParameterInfoArray.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/VirtualRuntimeParameterInfoArray.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/NativeFormat/NativeFormatRuntimeModule.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/NativeFormat/NativeFormatRuntimeModule.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/NativeFormat/NativeFormatRuntimeModule.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/NativeFormat/NativeFormatRuntimeModule.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs index c799a3db28a5e..c98f84cb4f6d3 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs @@ -25,8 +25,6 @@ protected RuntimeModule() public abstract override IEnumerable CustomAttributes { get; } - internal const string UnknownStringMessageInRAF = "Returns for modules with no file path"; - [RequiresAssemblyFiles(UnknownStringMessageInRAF)] public sealed override string FullyQualifiedName { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs index 9ca0900638452..3a49e94a9bd35 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/NativeFormat/NativeFormatMethodParameterInfo.cs @@ -64,7 +64,7 @@ public sealed override int MetadataToken protected sealed override IEnumerable TrueCustomAttributes => RuntimeCustomAttributeData.GetCustomAttributes(this.Reader, _parameter.CustomAttributes); - protected sealed override bool GetDefaultValueIfAvailable(bool raw, out object defaultValue) + protected sealed override bool GetDefaultValueIfAvailable(bool raw, out object? defaultValue) { return DefaultValueParser.GetDefaultValueIfAny(Reader, _parameter.DefaultValue, ParameterType, CustomAttributes, raw, out defaultValue); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs index 505f8109297a4..2f68d703a80df 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs @@ -36,7 +36,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs index cb53a3648beaa..b1c543238de15 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs @@ -34,7 +34,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs index 23d45271e63a3..d87734708878c 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs @@ -127,7 +127,7 @@ protected sealed override QSignatureTypeHandle PropertyTypeHandle } } - protected sealed override bool GetDefaultValueIfAny(bool raw, out object defaultValue) + protected sealed override bool GetDefaultValueIfAny(bool raw, out object? defaultValue) { return DefaultValueParser.GetDefaultValueIfAny(_reader, _property.DefaultValue, PropertyType, CustomAttributes, raw, out defaultValue); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs similarity index 96% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs index 32fb5ffa92644..440eb9487952d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs @@ -123,7 +123,7 @@ public sealed override MethodInfo GetMethod public sealed override Type[] GetRequiredCustomModifiers() => PropertyTypeHandle.GetCustomModifiers(ContextTypeInfo.TypeContext, optional: false); - public sealed override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) + public sealed override object? GetValue(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? index, CultureInfo culture) { if (_lazyGetterInvoker == null) { @@ -186,7 +186,7 @@ public sealed override MethodInfo SetMethod } } - public sealed override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) + public sealed override void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, object?[]? index, CultureInfo culture) { if (_lazySetterInvoker == null) { @@ -195,10 +195,10 @@ public sealed override void SetValue(object obj, object value, BindingFlags invo _lazySetterInvoker = Setter.GetUncachedMethodInvoker(Array.Empty(), this); } - object[] arguments; + object?[] arguments; if (index == null) { - arguments = new object[] { value }; + arguments = new object?[] { value }; } else { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs similarity index 96% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs index 4144e4ae4d9fa..b4789f8af68d1 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfo.cs @@ -58,7 +58,7 @@ protected sealed override int InternalGetHashCode() protected MetadataReader Reader { get; } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { if (_genericParameter.Name.IsNull(Reader)) return string.Empty; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForMethods.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs index 80b394decba94..18c175185421f 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeNamedTypeInfo.cs @@ -106,7 +106,7 @@ public sealed override int MetadataToken public sealed override string ToString() { - StringBuilder sb = null; + StringBuilder? sb = null; foreach (GenericParameterHandle genericParameterHandle in _typeDefinition.GenericParameters) { @@ -148,7 +148,7 @@ internal sealed override Type InternalDeclaringType { get { - RuntimeTypeInfo declaringType = null; + RuntimeTypeInfo? declaringType = null; TypeDefinitionHandle enclosingTypeDefHandle = _typeDefinition.EnclosingType; if (!enclosingTypeDefHandle.IsNull(_reader)) { @@ -168,7 +168,7 @@ internal sealed override string InternalFullNameOfAssembly } } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { ConstantStringValueHandle nameHandle = _typeDefinition.Name; string name = nameHandle.GetString(_reader); @@ -271,10 +271,10 @@ internal PropertyHandleCollection DeclaredPropertyHandles } } - public bool Equals(NativeFormatRuntimeNamedTypeInfo other) + public bool Equals(NativeFormatRuntimeNamedTypeInfo? other) { // RuntimeTypeInfo.Equals(object) is the one that encapsulates our unification strategy so defer to him. - object otherAsObject = other; + object? otherAsObject = other; return base.Equals(otherAsObject); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeTypeInfo.CoreGetDeclared.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeTypeInfo.CoreGetDeclared.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeTypeInfo.CoreGetDeclared.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeTypeInfo.CoreGetDeclared.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs index c6835e724ef94..1e560f7f6991d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs @@ -56,7 +56,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -172,7 +172,7 @@ internal sealed override Type InternalDeclaringType } } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { return GeneratedName; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeByRefTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeByRefTypeInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeByRefTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeByRefTypeInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs index 0e6fda3edaa72..1c767450be996 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs @@ -28,7 +28,7 @@ private RuntimeCLSIDTypeInfo(Guid clsid, string server) public sealed override bool ContainsGenericParameters => false; public sealed override string FullName => BaseType.FullName; public sealed override Guid GUID => _key.ClsId; - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) => BaseType.InternalGetNameIfAvailable(ref rootCauseForFailure); + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) => BaseType.InternalGetNameIfAvailable(ref rootCauseForFailure); public sealed override bool IsGenericTypeDefinition => false; public sealed override int MetadataToken => BaseType.MetadataToken; public sealed override string Namespace => BaseType.Namespace; @@ -39,7 +39,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs index 5cd6c23e8ca3a..a2a010de909ce 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs @@ -172,7 +172,7 @@ public sealed override string ToString() { // Get the FullName of the generic type definition in a pay-for-play safe way. RuntimeTypeInfo genericTypeDefinition = GenericTypeDefinitionTypeInfo; - string genericTypeDefinitionString = null; + string? genericTypeDefinitionString = null; if (genericTypeDefinition.InternalNameIfAvailable != null) // Want to avoid "cry-wolf" exceptions: if we can't even get the simple name, don't bother getting the FullName. { // Given our current pay for play policy, it should now be safe to attempt getting the FullName. (But guard with a try-catch in case this assumption is wrong.) @@ -259,7 +259,7 @@ internal sealed override string InternalFullNameOfAssembly } } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { return GenericTypeDefinitionTypeInfo.InternalGetNameIfAvailable(ref rootCauseForFailure); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.UnificationKey.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.UnificationKey.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.UnificationKey.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.UnificationKey.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs similarity index 95% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs index 05a65a8c80a97..67fe290b14997 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs @@ -77,7 +77,7 @@ public sealed override IEnumerable CustomAttributes { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -162,9 +162,9 @@ internal sealed override Type InternalDeclaringType } } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { - string elementTypeName = _key.ElementType.InternalGetNameIfAvailable(ref rootCauseForFailure); + string? elementTypeName = _key.ElementType.InternalGetNameIfAvailable(ref rootCauseForFailure); if (elementTypeName == null) { rootCauseForFailure = _key.ElementType; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs similarity index 96% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs index ddf99822a3ff3..ff70df743ffd2 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs @@ -47,10 +47,10 @@ public sealed override IEnumerable CustomAttributes } } - public bool Equals(RuntimeNamedTypeInfo other) + public bool Equals(RuntimeNamedTypeInfo? other) { // RuntimeTypeInfo.Equals(object) is the one that encapsulates our unification strategy so defer to him. - object otherAsObject = other; + object? otherAsObject = other; return base.Equals(otherAsObject); } @@ -93,10 +93,10 @@ public sealed override string FullName string name = Name; - Type declaringType = this.DeclaringType; - if (declaringType != null) + Type? declaringType = this.DeclaringType; + if (declaringType is not null) { - string declaringTypeFullName = declaringType.FullName; + string? declaringTypeFullName = declaringType.FullName; return declaringTypeFullName + "+" + name; } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs similarity index 98% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs index 2939a881e75d2..7176f4901bc6b 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs @@ -152,7 +152,7 @@ internal sealed override Type InternalDeclaringType } } - public sealed override string InternalGetNameIfAvailable(ref Type rootCauseForFailure) + internal sealed override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) { rootCauseForFailure = this; return null; diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimePointerTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimePointerTypeInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimePointerTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimePointerTypeInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.BindingFlags.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs similarity index 96% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs index 0fd1fccfc3574..d97fada651f20 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.CoreGetDeclared.cs @@ -38,7 +38,7 @@ internal IEnumerable CoreGetDeclaredConstructors(NameFilter opt if (definingType != null) { // If there is a definingType, we do not support Synthetic constructors - Debug.Assert(object.ReferenceEquals(SyntheticConstructors, Empty.Enumerable)); + Debug.Assert(object.ReferenceEquals(SyntheticConstructors, Array.Empty())); return definingType.CoreGetDeclaredConstructors(optionalNameFilter, this); } @@ -61,7 +61,7 @@ internal IEnumerable CoreGetDeclaredMethods(NameFilter optionalNameF if (definingType != null) { // If there is a definingType, we do not support Synthetic constructors - Debug.Assert(object.ReferenceEquals(SyntheticMethods, Empty.Enumerable)); + Debug.Assert(object.ReferenceEquals(SyntheticMethods, Array.Empty())); return definingType.CoreGetDeclaredMethods(optionalNameFilter, reflectedType, this); } @@ -85,7 +85,7 @@ internal IEnumerable CoreGetDeclaredEvents(NameFilter optionalNameFil { return definingType.CoreGetDeclaredEvents(optionalNameFilter, reflectedType, this); } - return Empty.Enumerable; + return Array.Empty(); } internal IEnumerable CoreGetDeclaredFields(NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) @@ -95,7 +95,7 @@ internal IEnumerable CoreGetDeclaredFields(NameFilter optionalNameFil { return definingType.CoreGetDeclaredFields(optionalNameFilter, reflectedType, this); } - return Empty.Enumerable; + return Array.Empty(); } internal IEnumerable CoreGetDeclaredProperties(NameFilter optionalNameFilter, RuntimeTypeInfo reflectedType) @@ -106,7 +106,7 @@ internal IEnumerable CoreGetDeclaredProperties(NameFilter optional return definingType.CoreGetDeclaredProperties(optionalNameFilter, reflectedType, this); } - return Empty.Enumerable; + return Array.Empty(); } // diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs similarity index 84% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs index 439343d33027b..832d741bbb774 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.GetMember.cs @@ -32,9 +32,9 @@ public sealed override MemberInfo[] GetMember(string name, MemberTypes type, Bin private MemberInfo[] GetMemberImpl(string optionalNameOrPrefix, MemberTypes type, BindingFlags bindingAttr) { bool prefixSearch = optionalNameOrPrefix != null && optionalNameOrPrefix.EndsWith("*", StringComparison.Ordinal); - string optionalName = prefixSearch ? null : optionalNameOrPrefix; + string? optionalName = prefixSearch ? null : optionalNameOrPrefix; - Func predicate = null; + Func? predicate = null; if (prefixSearch) { bool ignoreCase = (bindingAttr & BindingFlags.IgnoreCase) != 0; @@ -160,20 +160,5 @@ private M QueryMemberWithSameMetadataDefinitionAs(MemberInfo member) where M } return null; } - - // DynamicallyAccessedMemberTypes.All keeps more data than what a member can use: - // - Keeps info about interfaces - // - Complete Nested types (nested type body and all its members including other nested types) - // - Public and private base type information - // Instead, the GetAllMembers constant will keep: - // - The nested types body but not the members - // - Base type public information but not private information. This information should not - // be visible via the derived type and is ignored by reflection - internal const DynamicallyAccessedMemberTypes GetAllMembers = DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields | - DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents | - DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | - DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs similarity index 90% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs index 77dccda7966be..aa845932759a3 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.InvokeMember.cs @@ -12,9 +12,9 @@ namespace System.Reflection.Runtime.TypeInfos internal abstract partial class RuntimeTypeInfo { [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public sealed override object InvokeMember( - string name, BindingFlags bindingFlags, Binder binder, object target, - object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParams) + public sealed override object? InvokeMember( + string name, BindingFlags bindingFlags, Binder? binder, object? target, + object?[]? providedArgs, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParams) { const BindingFlags MemberBindingMask = (BindingFlags)0x000000FF; const BindingFlags InvocationMask = (BindingFlags)0x0000FF00; @@ -60,7 +60,7 @@ public sealed override object InvokeMember( #region COM Interop if (target != null && target.GetType().IsCOMObject) - throw new PlatformNotSupportedException(SR.Arg_PlatformNotSupportedInvokeMemberCom); + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); #endregion #region Check that any named paramters are not null @@ -98,13 +98,8 @@ public sealed override object InvokeMember( if (name.Length == 0 || name.Equals(@"[DISPID=0]")) { - name = GetDefaultMemberName(); - - if (name == null) - { - // in InvokeMember we always pretend there is a default member if none is provided and we make it ToString - name = "ToString"; - } + // in InvokeMember we always pretend there is a default member if none is provided and we make it ToString + name = GetDefaultMemberName() ?? "ToString"; } #endregion @@ -143,10 +138,8 @@ public sealed override object InvokeMember( #endregion #region Lookup Field - FieldInfo selFld = null; - FieldInfo[] flds = GetMember(name, MemberTypes.Field, bindingFlags) as FieldInfo[]; - - Debug.Assert(flds != null); + FieldInfo? selFld = null; + FieldInfo[] flds = (FieldInfo[])GetMember(name, MemberTypes.Field, bindingFlags); if (flds.Length == 1) { @@ -177,13 +170,15 @@ public sealed override object InvokeMember( if (idxCnt > 0) { + Debug.Assert(providedArgs != null); + // Verify that all of the index values are ints int[] idx = new int[idxCnt]; for (int i = 0; i < idxCnt; i++) { try { - idx[i] = ((IConvertible)providedArgs[i]).ToInt32(null); + idx[i] = ((IConvertible)providedArgs[i]!).ToInt32(null); } catch (InvalidCastException) { @@ -192,7 +187,7 @@ public sealed override object InvokeMember( } // Set or get the value... - Array a = (Array)selFld.GetValue(target); + Array a = (Array)selFld.GetValue(target)!; // Set or get the value in the array if ((bindingFlags & BindingFlags.GetField) != 0) @@ -264,15 +259,15 @@ public sealed override object InvokeMember( } #endregion - MethodInfo[] finalists = null; - MethodInfo finalist = null; + MethodInfo[]? finalists = null; + MethodInfo? finalist = null; #region BindingFlags.InvokeMethod if ((bindingFlags & BindingFlags.InvokeMethod) != 0) { #region Lookup Methods - MethodInfo[] semiFinalists = GetMember(name, MemberTypes.Method, bindingFlags) as MethodInfo[]; - LowLevelListWithIList results = null; + MethodInfo[] semiFinalists = (MethodInfo[])GetMember(name, MemberTypes.Method, bindingFlags); + LowLevelListWithIList? results = null; for (int i = 0; i < semiFinalists.Length; i++) { @@ -314,12 +309,12 @@ public sealed override object InvokeMember( if (finalist == null && isGetProperty || isSetProperty) { #region Lookup Property - PropertyInfo[] semiFinalists = GetMember(name, MemberTypes.Property, bindingFlags) as PropertyInfo[]; - LowLevelListWithIList results = null; + PropertyInfo[] semiFinalists = (PropertyInfo[])GetMember(name, MemberTypes.Property, bindingFlags); + LowLevelListWithIList? results = null; for (int i = 0; i < semiFinalists.Length; i++) { - MethodInfo semiFinalist; + MethodInfo? semiFinalist; if (isSetProperty) { @@ -386,10 +381,10 @@ public sealed override object InvokeMember( if (providedArgs == null) providedArgs = Array.Empty(); - object state = null; + object? state = null; - MethodBase invokeMethod = null; + MethodBase? invokeMethod = null; try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs, modifiers, culture, namedParams, out state); } catch (MissingMethodException) { } @@ -400,7 +395,7 @@ public sealed override object InvokeMember( //if (useCache && argCnt == invokeMethod.GetParameters().Length) // AddMethodToCache(name, bindingFlags, argCnt, providedArgs, invokeMethod); - object result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); + object? result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); if (state != null) binder.ReorderArgumentArray(ref providedArgs, state); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.TypeComponentsCache.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs similarity index 97% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs index 647b50e484a93..c52da3fb06481 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -183,7 +183,7 @@ public sealed override Type[] GenericTypeArguments | DynamicallyAccessedMemberTypes.PublicNestedTypes)] public sealed override MemberInfo[] GetDefaultMembers() { - string defaultMemberName = GetDefaultMemberName(); + string? defaultMemberName = GetDefaultMemberName(); return defaultMemberName != null ? GetMember(defaultMemberName) : Array.Empty(); } @@ -450,10 +450,10 @@ public sealed override Type MakeGenericType(params Type[] typeArguments) // the Type object for an inconsistent generic type - no MethodTable will ever match it so any attempt to "invoke" it // will throw an exception. bool foundSignatureType = false; - RuntimeTypeInfo[] runtimeTypeArguments = new RuntimeTypeInfo[typeArguments.Length]; + RuntimeTypeInfo?[] runtimeTypeArguments = new RuntimeTypeInfo[typeArguments.Length]; for (int i = 0; i < typeArguments.Length; i++) { - RuntimeTypeInfo runtimeTypeArgument = runtimeTypeArguments[i] = typeArguments[i] as RuntimeTypeInfo; + RuntimeTypeInfo? runtimeTypeArgument = runtimeTypeArguments[i] = typeArguments[i] as RuntimeTypeInfo; if (runtimeTypeArgument == null) { if (typeArguments[i] == null) @@ -465,7 +465,7 @@ public sealed override Type MakeGenericType(params Type[] typeArguments) } else { - throw new PlatformNotSupportedException(SR.PlatformNotSupported_MakeGenericType); // "PlatformNotSupported" because on desktop, passing in a foreign type is allowed and creates a RefEmit.TypeBuilder + throw new PlatformNotSupportedException(SR.Format(SR.Reflection_CustomReflectionObjectsNotSupported, typeArguments[i])); } } } @@ -475,7 +475,7 @@ public sealed override Type MakeGenericType(params Type[] typeArguments) for (int i = 0; i < typeArguments.Length; i++) { - RuntimeTypeInfo runtimeTypeArgument = runtimeTypeArguments[i]; + RuntimeTypeInfo runtimeTypeArgument = runtimeTypeArguments[i]!; // Desktop compatibility: Treat generic type definitions as a constructed generic type using the generic parameters as type arguments. if (runtimeTypeArgument.IsGenericTypeDefinition) @@ -485,7 +485,7 @@ public sealed override Type MakeGenericType(params Type[] typeArguments) throw new TypeLoadException(SR.CannotUseByRefLikeTypeInInstantiation); } - return this.GetConstructedGenericTypeWithTypeHandle(runtimeTypeArguments); + return this.GetConstructedGenericTypeWithTypeHandle(runtimeTypeArguments!); } public sealed override Type MakePointerType() @@ -505,8 +505,8 @@ public sealed override string Name { get { - Type rootCauseForFailure = null; - string name = InternalGetNameIfAvailable(ref rootCauseForFailure); + Type? rootCauseForFailure = null; + string? name = InternalGetNameIfAvailable(ref rootCauseForFailure); if (name == null) throw ReflectionCoreExecution.ExecutionDomain.CreateMissingMetadataException(rootCauseForFailure); return name; @@ -614,7 +614,7 @@ internal virtual RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers // internal abstract string InternalFullNameOfAssembly { get; } - public abstract override string InternalGetNameIfAvailable(ref Type rootCauseForFailure); + internal abstract override string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure); // // Left unsealed as HasElement types must override this. @@ -674,7 +674,7 @@ internal virtual IEnumerable SyntheticConstructors { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -685,7 +685,7 @@ internal virtual IEnumerable SyntheticMethods { get { - return Empty.Enumerable; + return Array.Empty(); } } @@ -776,7 +776,7 @@ internal virtual Type BaseTypeWithoutTheGenericParameterQuirk get { QTypeDefRefOrSpec baseTypeDefRefOrSpec = TypeRefDefOrSpecForBaseType; - RuntimeTypeInfo baseType = null; + RuntimeTypeInfo? baseType = null; if (!baseTypeDefRefOrSpec.IsValid) { baseType = baseTypeDefRefOrSpec.Resolve(this.TypeContext); @@ -785,10 +785,10 @@ internal virtual Type BaseTypeWithoutTheGenericParameterQuirk } } - private string GetDefaultMemberName() + private string? GetDefaultMemberName() { Type defaultMemberAttributeType = typeof(DefaultMemberAttribute); - for (Type type = this; type != null; type = type.BaseType) + for (Type type = this; type != null; type = type.BaseType!) { foreach (CustomAttributeData attribute in type.CustomAttributes) { @@ -800,7 +800,7 @@ private string GetDefaultMemberName() // constructor. Debug.Assert(attribute.ConstructorArguments.Count == 1 && attribute.ConstructorArguments[0].Value is string); - string memberName = (string)(attribute.ConstructorArguments[0].Value); + string? memberName = (string?)(attribute.ConstructorArguments[0].Value); return memberName; } } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/GetTypeOptions.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/GetTypeOptions.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/GetTypeOptions.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/GetTypeOptions.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs similarity index 100% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs index 91fcf3981c4b2..f4628ac0998c2 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs @@ -133,7 +133,7 @@ public sealed override Type ResolveType(Assembly containingAssemblyIfAny, GetTyp // Don't change these flags - we may be talking to a third party type here and we need to invoke it the way CoreClr does. BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic; - Type nestedType; + Type? nestedType; if (!getTypeOptions.IgnoreCase) { nestedType = declaringType.GetNestedType(_nestedTypeName, bf); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs index 507069941763b..d51157cc5b41d 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs @@ -198,7 +198,7 @@ private TypeName ParseGenericTypeArgument() } else if (token == TokenType.OpenSqBracket) { - RuntimeAssemblyName assemblyName = null; + RuntimeAssemblyName? assemblyName = null; NonQualifiedTypeName typeName = ParseNonQualifiedTypeName(); token = _lexer.GetNextToken(); if (token == TokenType.Comma) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs index a3847253fa3f0..6db9cb646f91a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs @@ -540,7 +540,7 @@ public static unsafe string ToHexStringUnsignedLong(ulong u, bool zeroPrepad, in for (; i >= 0; i--) { chars[i] = GetHexChar((uint)(u % 16)); - u = u / 16; + u /= 16; if ((i == 0) || (!zeroPrepad && (u == 0))) break; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs index 572a7f2829440..b1bb7853cd227 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs @@ -51,7 +51,14 @@ public void Throw(string libraryName) public void TrackErrorMessage(string? message) { - _errorMessage = message; + if (_errorMessage == null) + { + _errorMessage = Environment.NewLine; + } + if (!_errorMessage.Contains(message)) + { + _errorMessage += message + Environment.NewLine; + } } } } 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 6ab44352da6c9..aedbe429fd00f 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 @@ -285,14 +285,14 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary) [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhTypeCast_AreTypesEquivalent")] - private static unsafe extern bool AreTypesEquivalent(MethodTable* pType1, MethodTable* pType2); + private static extern unsafe bool AreTypesEquivalent(MethodTable* pType1, MethodTable* pType2); internal static unsafe bool AreTypesEquivalent(EETypePtr pType1, EETypePtr pType2) => AreTypesEquivalent(pType1.ToPointer(), pType2.ToPointer()); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhTypeCast_AreTypesAssignable")] - private static unsafe extern bool AreTypesAssignable(MethodTable* pSourceType, MethodTable* pTargetType); + private static extern unsafe bool AreTypesAssignable(MethodTable* pSourceType, MethodTable* pTargetType); internal static unsafe bool AreTypesAssignable(EETypePtr pSourceType, EETypePtr pTargetType) => AreTypesAssignable(pSourceType.ToPointer(), pTargetType.ToPointer()); @@ -303,18 +303,18 @@ internal static unsafe bool AreTypesAssignable(EETypePtr pSourceType, EETypePtr [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOf")] - private static unsafe extern object IsInstanceOf(MethodTable* pTargetType, object obj); + private static extern unsafe object IsInstanceOf(MethodTable* pTargetType, object obj); internal static unsafe object IsInstanceOf(EETypePtr pTargetType, object obj) => IsInstanceOf(pTargetType.ToPointer(), obj); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOfClass")] - private static unsafe extern object IsInstanceOfClass(MethodTable* pTargetType, object obj); + private static extern unsafe object IsInstanceOfClass(MethodTable* pTargetType, object obj); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhTypeCast_IsInstanceOfInterface")] - internal static unsafe extern object IsInstanceOfInterface(MethodTable* pTargetType, object obj); + internal static extern unsafe object IsInstanceOfInterface(MethodTable* pTargetType, object obj); internal static unsafe object IsInstanceOfInterface(EETypePtr pTargetType, object obj) => IsInstanceOfInterface(pTargetType.ToPointer(), obj); @@ -327,28 +327,28 @@ internal static unsafe object IsInstanceOfInterface(EETypePtr pTargetType, objec // [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhBoxAny")] - private static unsafe extern object RhBoxAny(ref byte pData, MethodTable* pEEType); + private static extern unsafe object RhBoxAny(ref byte pData, MethodTable* pEEType); internal static unsafe object RhBoxAny(ref byte pData, EETypePtr pEEType) => RhBoxAny(ref pData, pEEType.ToPointer()); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewObject")] - private static unsafe extern object RhNewObject(MethodTable* pEEType); + private static extern unsafe object RhNewObject(MethodTable* pEEType); internal static unsafe object RhNewObject(EETypePtr pEEType) => RhNewObject(pEEType.ToPointer()); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewArray")] - private static unsafe extern Array RhNewArray(MethodTable* pEEType, int length); + private static extern unsafe Array RhNewArray(MethodTable* pEEType, int length); internal static unsafe Array RhNewArray(EETypePtr pEEType, int length) => RhNewArray(pEEType.ToPointer(), length); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewString")] - internal static unsafe extern string RhNewString(MethodTable* pEEType, int length); + internal static extern unsafe string RhNewString(MethodTable* pEEType, int length); internal static unsafe string RhNewString(EETypePtr pEEType, int length) => RhNewString(pEEType.ToPointer(), length); @@ -535,19 +535,19 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhGetThreadStaticStorageForModule")] - internal static unsafe extern object[] RhGetThreadStaticStorageForModule(int moduleIndex); + internal static extern unsafe object[] RhGetThreadStaticStorageForModule(int moduleIndex); [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhSetThreadStaticStorageForModule")] - internal static unsafe extern bool RhSetThreadStaticStorageForModule(object[] storage, int moduleIndex); + internal static extern unsafe bool RhSetThreadStaticStorageForModule(object[] storage, int moduleIndex); [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhCurrentNativeThreadId")] - internal static unsafe extern IntPtr RhCurrentNativeThreadId(); + internal static extern unsafe IntPtr RhCurrentNativeThreadId(); [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhCurrentOSThreadId")] - internal static unsafe extern ulong RhCurrentOSThreadId(); + internal static extern unsafe ulong RhCurrentOSThreadId(); [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport("*", "RhGetCurrentThunkContext")] diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs index 83fce9bcd1cc1..433ecd599297b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs @@ -32,9 +32,8 @@ private RuntimeTypeHandle(IntPtr value) public override bool Equals(object? obj) { - if (obj is RuntimeTypeHandle) + if (obj is RuntimeTypeHandle handle) { - RuntimeTypeHandle handle = (RuntimeTypeHandle)obj; return Equals(handle); } return false; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Win32ThreadPoolPreAllocatedOverlapped.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Win32ThreadPoolPreAllocatedOverlapped.cs index 21235042d4246..4556882439198 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Win32ThreadPoolPreAllocatedOverlapped.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Win32ThreadPoolPreAllocatedOverlapped.cs @@ -7,7 +7,7 @@ namespace System.Threading { public sealed class PreAllocatedOverlapped : IDisposable, IDeferredDisposable { - internal unsafe readonly Win32ThreadPoolNativeOverlapped* _overlapped; + internal readonly unsafe Win32ThreadPoolNativeOverlapped* _overlapped; private DeferredDisposableLifetime _lifetime; [CLSCompliant(false)] diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.Internal.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.Internal.cs index 53867b10b0f3a..cad92a13fcc97 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.Internal.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Type.Internal.cs @@ -3,6 +3,8 @@ using System.Reflection; +using Internal.Runtime.Augments; + namespace System { // @@ -11,14 +13,24 @@ namespace System // Before adding new entries to this, ask yourself: is it ever referenced by System.Private.CoreLib? // If not, don't put it here. Put it on RuntimeTypeInfo instead. // - // Some of these "internal" methods are declared "public" because both Reflection.Core and System.Private.CoreLib need to reference them. - // public abstract partial class Type { + internal bool TryGetEEType(out EETypePtr eeType) + { + RuntimeTypeHandle typeHandle = RuntimeAugments.Callbacks.GetTypeHandleIfAvailable(this); + if (typeHandle.IsNull) + { + eeType = default(EETypePtr); + return false; + } + eeType = typeHandle.ToEETypePtr(); + return true; + } + /// /// Return Type.Name if sufficient metadata is available to do so - otherwise return null. /// - public string InternalNameIfAvailable + public string? InternalNameIfAvailable { get { @@ -30,7 +42,7 @@ public string InternalNameIfAvailable /// /// Return Type.Name if sufficient metadata is available to do so - otherwise return null and set "rootCauseForFailure" to an object to pass to MissingMetadataException. /// - public virtual string InternalGetNameIfAvailable(ref Type? rootCauseForFailure) => Name; + internal virtual string? InternalGetNameIfAvailable(ref Type? rootCauseForFailure) => Name; /// /// Return Type.Name if sufficient metadata is available to do so - otherwise return a default (non-null) string. @@ -39,8 +51,7 @@ internal string NameOrDefault { get { - string name = InternalNameIfAvailable; - return name != null ? name : DefaultTypeNameWhenMissingMetadata; + return InternalNameIfAvailable ?? DefaultTypeNameWhenMissingMetadata; } } @@ -73,7 +84,7 @@ internal string FullNameOrDefault // // The Project N version takes a raw metadata handle rather than a completed type so that it remains robust in the face of missing metadata. // - public string FormatTypeNameForReflection() + internal string FormatTypeNameForReflection() { try { @@ -87,8 +98,7 @@ public string FormatTypeNameForReflection() rootElementType = rootElementType.GetElementType()!; if (rootElementType.IsNested) { - string name = InternalNameIfAvailable; - return name == null ? DefaultTypeNameWhenMissingMetadata : name; + return InternalNameIfAvailable ?? DefaultTypeNameWhenMissingMetadata; } // Legacy: why removing "System"? Is it just because C# has keywords for these types? @@ -109,6 +119,6 @@ public string FormatTypeNameForReflection() } } - public const string DefaultTypeNameWhenMissingMetadata = "UnknownType"; + internal const string DefaultTypeNameWhenMissingMetadata = "UnknownType"; } } diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeTypeInfo.cs b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeTypeInfo.cs index 24506863ab20b..ad9f79c9be184 100644 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeTypeInfo.cs @@ -202,6 +202,36 @@ protected override bool IsPrimitiveImpl() return RuntimeAugments.IsPrimitive(_typeHandle); } + public override bool IsAssignableFrom([NotNullWhen(true)] Type c) + { + if (c == null) + return false; + + if (object.ReferenceEquals(c, this)) + return true; + + c = c.UnderlyingSystemType; + + Type typeInfo = c; + RuntimeTypeInfo toTypeInfo = this; + + if (typeInfo is not RuntimeType) + return false; // Desktop compat: If typeInfo is null, or implemented by a different Reflection implementation, return "false." + + RuntimeTypeInfo fromTypeInfo = (RuntimeTypeInfo)typeInfo; + + RuntimeTypeHandle toTypeHandle = toTypeInfo._typeHandle; + RuntimeTypeHandle fromTypeHandle = fromTypeInfo._typeHandle; + + if (RuntimeAugments.IsGenericTypeDefinition(toTypeHandle) || RuntimeAugments.IsGenericTypeDefinition(fromTypeHandle)) + throw new NotSupportedException(SR.Reflection_Disabled); + + if (RuntimeAugments.IsAssignableFrom(toTypeHandle, fromTypeHandle)) + return true; + + return false; + } + internal static RuntimeTypeInfo GetRuntimeTypeInfo(RuntimeTypeHandle typeHandle) { return RuntimeTypeTable.Table.GetOrAdd(new RuntimeTypeHandleKey(typeHandle)); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/ILLink/ILLink.Substitutions.xml b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/ILLink/ILLink.Substitutions.xml deleted file mode 100644 index f7df139a82b62..0000000000000 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/ILLink/ILLink.Substitutions.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Resources/Strings.resx b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Resources/Strings.resx deleted file mode 100644 index a19d41e9c09d8..0000000000000 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/Resources/Strings.resx +++ /dev/null @@ -1,369 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - A problem was found in this image's metadata. - - - Cannot create an instance of {0} because it is an abstract class. - - - Type initializer was not callable. - - - Cannot set a constant field. - - - A MemberInfo that matches '{0}' could not be found. - - - {0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true. - - - Method may only be called on a Type for which Type.IsGenericParameter is true. - - - A null or zero length string does not represent a valid Type. - - - The type or method has {1} generic parameter(s), but {0} generic argument(s) were provided. A generic argument must be provided for each generic parameter. - - - The object '{0}' was created by a custom ReflectionContext and cannot be used here. - - - The type '{0}' cannot be found. - - - The type '{0}' cannot be found in assembly '{1}'. - - - Cannot load assembly '{0}'. No metadata found for this assembly. - - - Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table. - - - Cannot bind to the target method because its signature is not compatible with that of the delegate type. - - - Type must derive from Delegate. - - - Cannot create a delegate on type '{0}' as it is missing metadata for the Invoke method. - - - An item with the same key has already been added. Key: {0} - - - The handle is invalid. - - - Type handle '{0}' and method handle with declaring type '{1}' are incompatible. Get RuntimeMethodHandle and declaring RuntimeTypeHandle off the same MethodBase. - - - Type handle '{0}' and field handle with declaring type '{1}' are incompatible. Get RuntimeFieldHandle and declaring RuntimeTypeHandle off the same FieldInfo. - - - Cannot resolve method {0} because the declaring type of the method handle is generic. Explicitly provide the declaring type to GetMethodFromHandle. - - - Cannot resolve field {0} because the declaring type of the field handle is generic. Explicitly provide the declaring type to GetFieldFromHandle. - - - Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true. - - - Type names passed to Assembly.GetType() must not specify an assembly. - - - Cannot add the event handler since no public add method exists for the event. - - - Cannot remove the event handler since no public remove method exists for the event. - - - {0} is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true. - - - PlatformNotSupported_MakeGenericType", @"MakeGenericType can only accept Type objects created by the runtime. - - - The type '{0}' may not be used as a type argument. - - - The type '{0}' may not be used as an array element type. - - - TypeHandles are not supported for types that return true for ContainsGenericParameters. - - - Must be an array type. - - - This operation is only valid on generic types. - - - Property get method not found. - - - Property set method not found. - - - Array may not be empty. - - - Member not found. - - - There is no metadata token available for the given member. - - - Field not found. - - - Type must be a type provided by the runtime. - - - ChangeType operation is not supported. - - - No parameterless constructor defined for this object. - - - Activation Attributes are not supported. - - - Vararg calling convention not supported. - - - Cannot create an instance of {0} because Type.ContainsGenericParameters is true. - - - Cannot dynamically create an instance of System.Void. - - - Method must be called on a Type for which Type.IsGenericParameter is false. - - - Must specify binding flags describing the invoke operation required (BindingFlags.InvokeMethod CreateInstance GetField SetField GetProperty SetProperty). - - - Named parameter array cannot be bigger than argument array. - - - Cannot specify both Get and Set on a property. - - - Cannot specify Set on a property and Invoke on a method. - - - Named parameter value must not be null. - - - Cannot specify both CreateInstance and another access type. - - - Cannot specify both Get and Set on a field. - - - Cannot specify both GetField and SetProperty. - - - Cannot specify both SetField and GetProperty. - - - Cannot specify Set on a Field and Invoke on a method. - - - All indexes must be of type Int32. - - - No arguments can be provided to Get a field value. - - - Only the field value can be specified to set a field value. - - - InvokeMember on a COM object is not supported on this platform. - - - Type must be a runtime Type object. - - - MethodInfo must be a runtime MethodInfo object. - - - Array must not be of length zero. - - - FieldInfo must be a runtime FieldInfo object. - - - Field in TypedReferences cannot be static. - - - FieldInfo does not match the target Type. - - - TypedReferences cannot be redefined as primitives. - - - TypedReference can only be made on nested value Types. - - - The TypedReference must be initialized. - - - Cannot create an abstract class. - - - Cannot create an instance of an interface. - - - Cannot create a byref of a byref: {0} - - - Cannot create a pointer to a byref: {0} - - - Literal value was not found. - - - Cannot create boxed ByRef-like values. - - - Cannot instantiate a generic type on a byref-like type. - - - Non-static method requires a target. - - - Object does not match target type. - - - Nullable object must have a value. - - - Interface maps for generic interfaces on arrays cannot be retrieved. - - - CodeBase is not supported on assemblies loaded from a single-file bundle. - - diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj deleted file mode 100644 index a770233c1ccac..0000000000000 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - $(NoWarn);CS0672 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System\NotImplemented.cs - - - - System\Collections\Generic\LowLevelList.cs - - - System\Collections\Generic\LowLevelDictionary.cs - - - Internal\LowLevelLinq\LowLevelEnumerable.cs - - - Internal\LowLevelLinq\LowLevelEnumerable.ToArray.cs - - - System\Collections\HashHelpers.cs - - - System\Collections\Generic\EnumerableExtensions.cs - - - System\Collections\Generic\Empty.cs - - - System\Collections\Concurrent\ConcurrentUnifier.cs - - - System\Collections\Concurrent\ConcurrentUnifierW.cs - - - System\Collections\Concurrent\ConcurrentUnifierWKeyed.cs - - - System\Collections\Concurrent\IKeyedItem.cs - - - System\Runtime\CompilerServices\DeveloperExperienceModeOnlyAttribute.cs - - - System\Runtime\CompilerServices\DeveloperExperienceState.cs - - - System\Runtime\CompilerServices\__BlockAllReflectionAttribute.cs - - - - - - diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs b/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs deleted file mode 100644 index 61a8b4d76801e..0000000000000 --- a/src/coreclr/nativeaot/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NonOverriddenApis.cs +++ /dev/null @@ -1,217 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// Why this file exists: -// -// Because the Reflection base types have so many overridable members, it becomes difficult to distinguish -// members we decided not to override vs. those we forgot to override. It would be nice if C# had a construct to -// tell the reader (and Intellisense) that we've made an explicit decision *not* to override an inherited member, -// but since it doesn't, we'll make do with this instead. -// -// In DEBUG builds, we'll add a base-delegating override so that it's clear we made an explicit decision -// to accept the base class's implementation. In RELEASE builds, we'll #if'd these out to avoid the extra metadata and runtime -// cost. That way, every overridable member is accounted for (i.e. the codebase should always be kept in a state -// where hitting "override" + SPACE never brings up additional suggestions in Intellisense.) -// -// To avoid introducing inadvertent inconsistencies between DEBUG and RELEASE behavior due to the fragile base class -// problem, only do this for public or protected members that already exist on the public api type. Since we know -// we'll never remove those members, we'll avoid the problem of "base" being compile-bound to something different -// from the runtime "base." -// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Reflection; -using System.Globalization; -using System.Collections.Generic; - -namespace System.Reflection.Runtime.Assemblies -{ - internal partial class RuntimeAssemblyInfo - { -#if DEBUG - [RequiresUnreferencedCode("Assembly.CreateInstance is not supported with trimming. Use Type.GetType instead.")] - public sealed override object CreateInstance(string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes) => base.CreateInstance(typeName, ignoreCase, bindingAttr, binder, args, culture, activationAttributes); - [RequiresUnreferencedCode("Types might be removed")] - public sealed override Type GetType(string name) => base.GetType(name); - [RequiresUnreferencedCode("Types might be removed")] - public sealed override Type GetType(string name, bool throwOnError) => base.GetType(name, throwOnError); - public sealed override bool IsDynamic => base.IsDynamic; - public sealed override string ToString() => base.ToString(); - [RequiresAssemblyFilesAttribute("The code will return an empty string for assemblies embedded in a single-file app")] -#pragma warning disable SYSLIB0012 - public sealed override string EscapedCodeBase => base.EscapedCodeBase; -#pragma warning restore SYSLIB0012 - [RequiresAssemblyFiles("The code will throw for assemblies embedded in a single-file app")] - public sealed override FileStream[] GetFiles() => base.GetFiles(); -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.MethodInfos -{ - internal abstract partial class RuntimeConstructorInfo - { -#if DEBUG - public sealed override MemberTypes MemberType => base.MemberType; -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.CustomAttributes -{ - internal abstract partial class RuntimeCustomAttributeData - { -#if DEBUG - public sealed override bool Equals(object obj) => base.Equals(obj); - public sealed override int GetHashCode() => base.GetHashCode(); -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.EventInfos -{ - internal abstract partial class RuntimeEventInfo - { -#if DEBUG - public sealed override MemberTypes MemberType => base.MemberType; - public sealed override bool IsMulticast => base.IsMulticast; - public sealed override void AddEventHandler(object target, Delegate handler) => base.AddEventHandler(target, handler); - public sealed override void RemoveEventHandler(object target, Delegate handler) => base.RemoveEventHandler(target, handler); -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.FieldInfos -{ - internal abstract partial class RuntimeFieldInfo - { -#if DEBUG - public sealed override MemberTypes MemberType => base.MemberType; - public sealed override bool IsSecurityCritical => base.IsSecurityCritical; - public sealed override bool IsSecuritySafeCritical => base.IsSecuritySafeCritical; - public sealed override bool IsSecurityTransparent => base.IsSecurityTransparent; -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.MethodInfos -{ - internal abstract partial class RuntimeMethodInfo - { -#if DEBUG - public sealed override MemberTypes MemberType => base.MemberType; -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.Modules -{ - internal abstract partial class RuntimeModule - { -#if DEBUG - [RequiresUnreferencedCode("Types might be removed")] - public sealed override Type[] FindTypes(TypeFilter filter, object filterCriteria) => base.FindTypes(filter, filterCriteria); - [RequiresUnreferencedCode("Types might be removed")] - public sealed override Type GetType(string className) => base.GetType(className); - [RequiresUnreferencedCode("Types might be removed")] - public sealed override Type GetType(string className, bool ignoreCase) => base.GetType(className, ignoreCase); - public sealed override string ToString() => base.ToString(); -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.ParameterInfos -{ - internal abstract partial class RuntimeParameterInfo - { -#if DEBUG -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.PropertyInfos -{ - internal abstract partial class RuntimePropertyInfo - { -#if DEBUG - public sealed override MemberTypes MemberType => base.MemberType; - public sealed override object GetValue(object obj, object[] index) => base.GetValue(obj, index); - public sealed override void SetValue(object obj, object value, object[] index) => base.SetValue(obj, value, index); -#endif //DEBUG - } -} - -namespace System.Reflection.Runtime.TypeInfos -{ - internal abstract partial class RuntimeTypeInfo - { -#if DEBUG - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] - public sealed override Type[] FindInterfaces(TypeFilter filter, object filterCriteria) => base.FindInterfaces(filter, filterCriteria); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public sealed override MemberInfo[] FindMembers(MemberTypes memberType, BindingFlags bindingAttr, MemberFilter filter, object filterCriteria) => base.FindMembers(memberType, bindingAttr, filter, filterCriteria); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents)] - public sealed override EventInfo[] GetEvents() => base.GetEvents(); - protected sealed override bool IsContextfulImpl() => base.IsContextfulImpl(); - public sealed override bool IsSubclassOf(Type c) => base.IsSubclassOf(c); - protected sealed override bool IsMarshalByRefImpl() => base.IsMarshalByRefImpl(); - public sealed override bool IsInstanceOfType(object o) => base.IsInstanceOfType(o); - public sealed override bool IsSerializable => base.IsSerializable; - public sealed override bool IsEquivalentTo(Type other) => base.IsEquivalentTo(other); // Note: If we enable COM type equivalence, this is no longer the correct implementation. - public sealed override bool IsSignatureType => base.IsSignatureType; - - public sealed override IEnumerable DeclaredConstructors - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - get => base.DeclaredConstructors; - } - public sealed override IEnumerable DeclaredEvents - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] - get => base.DeclaredEvents; - } - public sealed override IEnumerable DeclaredFields - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] - get => base.DeclaredFields; - } - public sealed override IEnumerable DeclaredMembers - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - get => base.DeclaredMembers; - } - public sealed override IEnumerable DeclaredMethods - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] - get => base.DeclaredMethods; - } - public sealed override IEnumerable DeclaredNestedTypes - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - get => base.DeclaredNestedTypes; - } - public sealed override IEnumerable DeclaredProperties - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] - get => base.DeclaredProperties; - } - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)] - public sealed override EventInfo GetDeclaredEvent(string name) => base.GetDeclaredEvent(name); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] - public sealed override FieldInfo GetDeclaredField(string name) => base.GetDeclaredField(name); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] - public sealed override MethodInfo GetDeclaredMethod(string name) => base.GetDeclaredMethod(name); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] - public sealed override TypeInfo GetDeclaredNestedType(string name) => base.GetDeclaredNestedType(name); - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] - public sealed override PropertyInfo GetDeclaredProperty(string name) => base.GetDeclaredProperty(name); - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] - public sealed override IEnumerable GetDeclaredMethods(string name) => base.GetDeclaredMethods(name); -#endif //DEBUG - } -} diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs index 4b867227bf3c9..7bbc2de4e88f1 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/ExecutionEnvironmentImplementation.MappingTables.cs @@ -105,7 +105,7 @@ private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo modu /// /// Runtime handle of the type in question /// TypeDef handle for the type - public sealed unsafe override bool TryGetMetadataForNamedType(RuntimeTypeHandle runtimeTypeHandle, out QTypeDefinition qTypeDefinition) + public sealed override unsafe bool TryGetMetadataForNamedType(RuntimeTypeHandle runtimeTypeHandle, out QTypeDefinition qTypeDefinition) { Debug.Assert(!RuntimeAugments.IsGenericType(runtimeTypeHandle)); return TypeLoaderEnvironment.Instance.TryGetMetadataForNamedType(runtimeTypeHandle, out qTypeDefinition); @@ -117,7 +117,7 @@ public sealed unsafe override bool TryGetMetadataForNamedType(RuntimeTypeHandle // Preconditions: // runtimeTypeHandle is a typedef or a generic type instance (not a constructed type such as an array) // - public sealed unsafe override bool IsReflectionBlocked(RuntimeTypeHandle runtimeTypeHandle) + public sealed override unsafe bool IsReflectionBlocked(RuntimeTypeHandle runtimeTypeHandle) { // For generic types, use the generic type definition runtimeTypeHandle = GetTypeDefinition(runtimeTypeHandle); @@ -165,7 +165,7 @@ public sealed unsafe override bool IsReflectionBlocked(RuntimeTypeHandle runtime /// /// TypeDef handle for the type to look up /// Runtime type handle (MethodTable) for the given type - public sealed unsafe override bool TryGetNamedTypeForMetadata(QTypeDefinition qTypeDefinition, out RuntimeTypeHandle runtimeTypeHandle) + public sealed override unsafe bool TryGetNamedTypeForMetadata(QTypeDefinition qTypeDefinition, out RuntimeTypeHandle runtimeTypeHandle) { return TypeLoaderEnvironment.Instance.TryGetOrCreateNamedTypeForMetadata(qTypeDefinition, out runtimeTypeHandle); } @@ -182,7 +182,7 @@ public sealed unsafe override bool TryGetNamedTypeForMetadata(QTypeDefinition qT /// MethodTable of the type in question /// Metadata reader for the type /// Located TypeRef handle - public sealed unsafe override bool TryGetTypeReferenceForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeReferenceHandle typeRefHandle) + public sealed override unsafe bool TryGetTypeReferenceForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeReferenceHandle typeRefHandle) { return TypeLoaderEnvironment.TryGetTypeReferenceForNamedType(runtimeTypeHandle, out metadataReader, out typeRefHandle); } @@ -205,7 +205,7 @@ public sealed unsafe override bool TryGetTypeReferenceForNamedType(RuntimeTypeHa /// Metadata reader for module containing the type reference /// TypeRef handle to look up /// Resolved MethodTable for the type reference - public sealed unsafe override bool TryGetNamedTypeForTypeReference(MetadataReader metadataReader, TypeReferenceHandle typeRefHandle, out RuntimeTypeHandle runtimeTypeHandle) + public sealed override unsafe bool TryGetNamedTypeForTypeReference(MetadataReader metadataReader, TypeReferenceHandle typeRefHandle, out RuntimeTypeHandle runtimeTypeHandle) { return TypeLoaderEnvironment.TryGetNamedTypeForTypeReference(metadataReader, typeRefHandle, out runtimeTypeHandle); } @@ -219,7 +219,7 @@ public sealed unsafe override bool TryGetNamedTypeForTypeReference(MetadataReade // // This is not equivalent to calling TryGetMultiDimTypeForElementType() with a rank of 1! // - public sealed unsafe override bool TryGetArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, out RuntimeTypeHandle arrayTypeHandle) + public sealed override unsafe bool TryGetArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, out RuntimeTypeHandle arrayTypeHandle) { if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle)) { @@ -240,7 +240,7 @@ public sealed unsafe override bool TryGetArrayTypeForElementType(RuntimeTypeHand // // This is not equivalent to calling TryGetMultiDimTypeElementType() with a rank of 1! // - public sealed unsafe override bool TryGetArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, out RuntimeTypeHandle elementTypeHandle) + public sealed override unsafe bool TryGetArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, out RuntimeTypeHandle elementTypeHandle) { elementTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(arrayTypeHandle); return true; @@ -256,7 +256,7 @@ public sealed unsafe override bool TryGetArrayTypeElementType(RuntimeTypeHandle // // Calling this with rank 1 is not equivalent to calling TryGetArrayTypeForElementType()! // - public sealed unsafe override bool TryGetMultiDimArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, int rank, out RuntimeTypeHandle arrayTypeHandle) + public sealed override unsafe bool TryGetMultiDimArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, int rank, out RuntimeTypeHandle arrayTypeHandle) { if (RuntimeAugments.IsGenericTypeDefinition(elementTypeHandle)) { @@ -279,7 +279,7 @@ public sealed unsafe override bool TryGetMultiDimArrayTypeForElementType(Runtime // Preconditions: // targetTypeHandle is a valid RuntimeTypeHandle. // - public sealed unsafe override bool TryGetPointerTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle pointerTypeHandle) + public sealed override unsafe bool TryGetPointerTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle pointerTypeHandle) { return TypeLoaderEnvironment.Instance.TryGetPointerTypeForTargetType(targetTypeHandle, out pointerTypeHandle); } @@ -291,7 +291,7 @@ public sealed unsafe override bool TryGetPointerTypeForTargetType(RuntimeTypeHan // Preconditions: // pointerTypeHandle is a valid RuntimeTypeHandle of type pointer. // - public sealed unsafe override bool TryGetPointerTypeTargetType(RuntimeTypeHandle pointerTypeHandle, out RuntimeTypeHandle targetTypeHandle) + public sealed override unsafe bool TryGetPointerTypeTargetType(RuntimeTypeHandle pointerTypeHandle, out RuntimeTypeHandle targetTypeHandle) { targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(pointerTypeHandle); return true; @@ -304,7 +304,7 @@ public sealed unsafe override bool TryGetPointerTypeTargetType(RuntimeTypeHandle // Preconditions: // targetTypeHandle is a valid RuntimeTypeHandle. // - public sealed unsafe override bool TryGetByRefTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle byRefTypeHandle) + public sealed override unsafe bool TryGetByRefTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle byRefTypeHandle) { return TypeLoaderEnvironment.Instance.TryGetByRefTypeForTargetType(targetTypeHandle, out byRefTypeHandle); } @@ -316,7 +316,7 @@ public sealed unsafe override bool TryGetByRefTypeForTargetType(RuntimeTypeHandl // Preconditions: // byRefTypeHandle is a valid RuntimeTypeHandle of a byref. // - public sealed unsafe override bool TryGetByRefTypeTargetType(RuntimeTypeHandle byRefTypeHandle, out RuntimeTypeHandle targetTypeHandle) + public sealed override unsafe bool TryGetByRefTypeTargetType(RuntimeTypeHandle byRefTypeHandle, out RuntimeTypeHandle targetTypeHandle) { targetTypeHandle = RuntimeAugments.GetRelatedParameterTypeHandle(byRefTypeHandle); return true; @@ -330,7 +330,7 @@ public sealed unsafe override bool TryGetByRefTypeTargetType(RuntimeTypeHandle b // runtimeTypeDefinitionHandle is a valid RuntimeTypeHandle for a generic type. // genericTypeArgumentHandles is an array of valid RuntimeTypeHandles. // - public sealed unsafe override bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle) + public sealed override unsafe bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle) { if (TypeLoaderEnvironment.Instance.TryLookupConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle)) { @@ -1400,7 +1400,7 @@ public sealed override FieldAccessor TryGetFieldAccessor( // // This resolves RuntimeMethodHandles for methods declared on non-generic types (declaringTypeHandle is an output of this method.) // - public sealed unsafe override bool TryGetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles) + public sealed override unsafe bool TryGetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out QMethodDefinition methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles) { MethodNameAndSignature nameAndSignature; methodHandle = default(QMethodDefinition); @@ -1421,7 +1421,7 @@ public sealed override bool TryGetMethodFromHandleAndType(RuntimeMethodHandle ru // // This resolves RuntimeFieldHandles for fields declared on non-generic types (declaringTypeHandle is an output of this method.) // - public sealed unsafe override bool TryGetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle) + public sealed override unsafe bool TryGetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle) { fieldHandle = default(FieldHandle); diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/PointerTypeFieldAccessorForStaticFields.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/PointerTypeFieldAccessorForStaticFields.cs index a951827597362..224ad076cbce7 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/PointerTypeFieldAccessorForStaticFields.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/PointerTypeFieldAccessorForStaticFields.cs @@ -16,7 +16,7 @@ public PointerTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr stati { } - protected sealed unsafe override object GetFieldBypassCctor() + protected sealed override unsafe object GetFieldBypassCctor() { if (FieldBase == FieldTableFlags.GCStatic) { @@ -33,7 +33,7 @@ protected sealed unsafe override object GetFieldBypassCctor() return RuntimeAugments.LoadPointerTypeField(threadStaticRegion, FieldOffset, FieldTypeHandle); } - protected sealed unsafe override void UncheckedSetFieldBypassCctor(object value) + protected sealed override unsafe void UncheckedSetFieldBypassCctor(object value) { if (FieldBase == FieldTableFlags.GCStatic) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ReferenceTypeFieldAccessorForStaticFields.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ReferenceTypeFieldAccessorForStaticFields.cs index ad9a193e860e1..5233fe28d5dab 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ReferenceTypeFieldAccessorForStaticFields.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ReferenceTypeFieldAccessorForStaticFields.cs @@ -16,7 +16,7 @@ public ReferenceTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr sta { } - protected sealed unsafe override object GetFieldBypassCctor() + protected sealed override unsafe object GetFieldBypassCctor() { if (FieldBase == FieldTableFlags.GCStatic) { @@ -33,7 +33,7 @@ protected sealed unsafe override object GetFieldBypassCctor() return RuntimeAugments.LoadReferenceTypeField(threadStaticRegion, FieldOffset); } - protected sealed unsafe override void UncheckedSetFieldBypassCctor(object value) + protected sealed override unsafe void UncheckedSetFieldBypassCctor(object value) { if (FieldBase == FieldTableFlags.GCStatic) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ValueTypeFieldAccessorForStaticFields.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ValueTypeFieldAccessorForStaticFields.cs index ae90edc558c6d..28765e89600db 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ValueTypeFieldAccessorForStaticFields.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/FieldAccessors/ValueTypeFieldAccessorForStaticFields.cs @@ -16,7 +16,7 @@ public ValueTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr statics { } - protected sealed unsafe override object GetFieldBypassCctor() + protected sealed override unsafe object GetFieldBypassCctor() { if (FieldBase == FieldTableFlags.GCStatic) { @@ -33,7 +33,7 @@ protected sealed unsafe override object GetFieldBypassCctor() return RuntimeAugments.LoadValueTypeField(threadStaticRegion, FieldOffset, FieldTypeHandle); } - protected sealed unsafe override void UncheckedSetFieldBypassCctor(object value) + protected sealed override unsafe void UncheckedSetFieldBypassCctor(object value) { if (FieldBase == FieldTableFlags.GCStatic) { diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/PayForPlayExperience/MissingMetadataExceptionCreator.cs b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/PayForPlayExperience/MissingMetadataExceptionCreator.cs index db347ad0b787b..46b245f9db743 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/PayForPlayExperience/MissingMetadataExceptionCreator.cs +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/Internal/Reflection/Execution/PayForPlayExperience/MissingMetadataExceptionCreator.cs @@ -15,17 +15,17 @@ namespace Internal.Reflection.Execution.PayForPlayExperience { public static class MissingMetadataExceptionCreator { - internal static MissingMetadataException Create(string resourceId, MemberInfo pertainant) + internal static MissingMetadataException Create(string resourceId, MemberInfo? pertainant) { return CreateFromMetadataObject(resourceId, pertainant); } - internal static MissingMetadataException Create(TypeInfo pertainant) + internal static MissingMetadataException Create(TypeInfo? pertainant) { return CreateFromMetadataObject(SR.Reflection_InsufficientMetadata_EdbNeeded, pertainant); } - internal static MissingMetadataException Create(TypeInfo pertainant, string nestedTypeName) + internal static MissingMetadataException Create(TypeInfo? pertainant, string nestedTypeName) { if (pertainant == null) return new MissingMetadataException(SR.Format(SR.Reflection_InsufficientMetadata_NoHelpAvailable, "")); @@ -40,7 +40,7 @@ internal static MissingMetadataException Create(TypeInfo pertainant, string nest } } - internal static MissingMetadataException Create(Type pertainant) + internal static MissingMetadataException Create(Type? pertainant) { return CreateFromMetadataObject(SR.Reflection_InsufficientMetadata_EdbNeeded, pertainant); } @@ -50,7 +50,7 @@ internal static MissingMetadataException Create(RuntimeTypeHandle pertainant) return CreateFromMetadataObject(SR.Reflection_InsufficientMetadata_EdbNeeded, pertainant); } - private static MissingMetadataException CreateFromString(string pertainant) + private static MissingMetadataException CreateFromString(string? pertainant) { if (pertainant == null) return new MissingMetadataException(SR.Format(SR.Reflection_InsufficientMetadata_NoHelpAvailable, "")); @@ -71,7 +71,7 @@ internal static MissingMetadataException CreateMissingConstructedGenericTypeExce return CreateFromString(s); } - internal static MissingMetadataException CreateFromMetadataObject(string resourceId, object pertainant) + internal static MissingMetadataException CreateFromMetadataObject(string resourceId, object? pertainant) { if (pertainant == null) return new MissingMetadataException(SR.Format(SR.Reflection_InsufficientMetadata_NoHelpAvailable, "")); @@ -99,16 +99,13 @@ public static string ComputeUsefulPertainantIfPossible(object pertainant) return type.ToDisplayStringIfAvailable(null); } - if (pertainant is MemberInfo) + if (pertainant is MemberInfo memberInfo) { - MemberInfo memberInfo = (MemberInfo)pertainant; - StringBuilder friendlyName = new StringBuilder(memberInfo.DeclaringType.ToDisplayStringIfAvailable(null)); friendlyName.Append('.'); friendlyName.Append(memberInfo.Name); - if (pertainant is MethodBase) + if (pertainant is MethodBase method) { - MethodBase method = (MethodBase)pertainant; bool first; // write out generic parameters @@ -249,7 +246,7 @@ internal static string ToDisplayStringIfAvailable(this Type type, List gene { genericParameterOffsets.Add(s.Length); if (genericArgCount > 0) - s = s + ","; + s += ","; } s += "]"; } @@ -283,7 +280,7 @@ private static string CreateConstructedGenericTypeStringIfAvailable(Type generic // Similarly, if we found too few, add them at the end. while (genericTypeArguments.Length > genericParameterOffsets.Count) { - genericTypeDefinitionString = genericTypeDefinitionString + ","; + genericTypeDefinitionString += ","; genericParameterOffsets.Add(genericTypeDefinitionString.Length); } diff --git a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj index e8b65e31ca05f..d7883b5f2ebe7 100644 --- a/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj +++ b/src/coreclr/nativeaot/System.Private.Reflection.Execution/src/System.Private.Reflection.Execution.csproj @@ -2,7 +2,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs index f5bdf03faa20a..c16a125c3474e 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs @@ -941,7 +941,7 @@ private static unsafe int CreateGCDesc(LowLevelList bitfield, int size, bo } else { - seriesSize = seriesSize - size; + seriesSize -= size; *ptr-- = (void*)seriesOffset; *ptr-- = (void*)seriesSize; } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionary.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionary.cs index eed0b97d01e92..56a7fd8aa6e96 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionary.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionary.cs @@ -59,7 +59,7 @@ public GenericMethodDictionary(GenericDictionaryCell[] cells) : base(cells) { } - public unsafe override IntPtr Allocate() + public override unsafe IntPtr Allocate() { Debug.Assert(_addressOfFirstCellSlot == IntPtr.Zero); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs index 68b8ffcf9b3a0..69df4c61d68df 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs @@ -23,7 +23,7 @@ public abstract class GenericDictionaryCell { internal abstract void Prepare(TypeBuilder builder); internal abstract IntPtr Create(TypeBuilder builder); - internal unsafe virtual void WriteCellIntoDictionary(TypeBuilder typeBuilder, IntPtr* pDictionary, int slotIndex) + internal virtual unsafe void WriteCellIntoDictionary(TypeBuilder typeBuilder, IntPtr* pDictionary, int slotIndex) { pDictionary[slotIndex] = Create(typeBuilder); } @@ -57,7 +57,7 @@ internal override IntPtr Create(TypeBuilder builder) throw new NotSupportedException(); } - internal unsafe override void WriteCellIntoDictionary(TypeBuilder typeBuilder, IntPtr* pDictionary, int slotIndex) + internal override unsafe void WriteCellIntoDictionary(TypeBuilder typeBuilder, IntPtr* pDictionary, int slotIndex) { pDictionary[slotIndex] = new IntPtr(pDictionary + OtherDictionarySlot); } @@ -289,7 +289,7 @@ private class MethodDictionaryCell : GenericDictionaryCell { internal InstantiatedMethod GenericMethod; - internal unsafe override void Prepare(TypeBuilder builder) + internal override unsafe void Prepare(TypeBuilder builder) { if (GenericMethod.IsCanonicalMethod(CanonicalFormKind.Any)) Environment.FailFast("Method dictionaries of canonical methods do not exist"); @@ -312,7 +312,7 @@ private class FieldLdTokenCell : GenericDictionaryCell internal TypeDesc ContainingType; internal IntPtr FieldName; - internal unsafe override void Prepare(TypeBuilder builder) + internal override unsafe void Prepare(TypeBuilder builder) { if (ContainingType.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Ldtoken is not permitted for a canonical field"); @@ -336,7 +336,7 @@ private class MethodLdTokenCell : GenericDictionaryCell internal IntPtr MethodName; internal RuntimeSignature MethodSignature; - internal unsafe override void Prepare(TypeBuilder builder) + internal override unsafe void Prepare(TypeBuilder builder) { if (Method.IsCanonicalMethod(CanonicalFormKind.Any)) Environment.FailFast("Ldtoken is not permitted for a canonical method"); @@ -532,11 +532,11 @@ public static GenericDictionaryCell CreateIntPtrCell(IntPtr ptrValue) private class IntPtrCell : GenericDictionaryCell { internal IntPtr Value; - internal unsafe override void Prepare(TypeBuilder builder) + internal override unsafe void Prepare(TypeBuilder builder) { } - internal unsafe override IntPtr Create(TypeBuilder builder) + internal override unsafe IntPtr Create(TypeBuilder builder) { return Value; } @@ -567,7 +567,7 @@ private class MethodCell : GenericDictionaryCell private MethodDesc _methodToUseForInstantiatingParameters; private IntPtr _exactFunctionPointer; - internal unsafe override void Prepare(TypeBuilder builder) + internal override unsafe void Prepare(TypeBuilder builder) { _methodToUseForInstantiatingParameters = Method; @@ -761,7 +761,7 @@ private bool NeedsDictionaryParameterToCallCanonicalVersion(MethodDesc method) return Method.OwningType.IsValueType && !Method.UnboxingStub; } - internal unsafe override IntPtr Create(TypeBuilder builder) + internal override unsafe IntPtr Create(TypeBuilder builder) { if (_exactFunctionPointer != IntPtr.Zero) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs index f6e52ed013dd2..efafe262ed4d5 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/ModuleList.cs @@ -710,10 +710,7 @@ public void RegisterNewModules(ModuleType moduleType) updatedModules[oldModuleCount + newModuleIndex] = newModuleInfo; - if (_moduleRegistrationCallbacks != null) - { - _moduleRegistrationCallbacks(newModuleInfo); - } + _moduleRegistrationCallbacks?.Invoke(newModuleInfo); } // Atomically update the module map @@ -734,10 +731,7 @@ public void RegisterModule(ModuleInfo newModuleInfo) Array.Copy(_loadedModuleMap.Modules, 0, updatedModules, 0, oldModuleCount); } updatedModules[oldModuleCount] = newModuleInfo; - if (_moduleRegistrationCallbacks != null) - { - _moduleRegistrationCallbacks(newModuleInfo); - } + _moduleRegistrationCallbacks?.Invoke(newModuleInfo); // Atomically update the module map _loadedModuleMap = new ModuleMap(updatedModules); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs index 054a5ec9956db..72609631283c2 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldAlgorithm.cs @@ -19,7 +19,7 @@ internal class NativeLayoutFieldAlgorithm : FieldLayoutAlgorithm private NoMetadataFieldLayoutAlgorithm _noMetadataFieldLayoutAlgorithm = new NoMetadataFieldLayoutAlgorithm(); private const int InstanceAlignmentEntry = 4; - public unsafe override bool ComputeContainsGCPointers(DefType type) + public override unsafe bool ComputeContainsGCPointers(DefType type) { if (type.IsTemplateCanonical()) { @@ -430,7 +430,7 @@ internal void GetFieldSizeAlignment(TypeDesc fieldType, out LayoutInt size, out alignment = fieldDefType.InstanceFieldAlignment; } - public unsafe override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) + public override unsafe ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { // Use this constant to make the code below more laconic const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldDesc.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldDesc.cs index 056cb26016ef4..b658f1dc49c3a 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldDesc.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutFieldDesc.cs @@ -39,6 +39,8 @@ public override TypeDesc FieldType } } + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => null; + public override bool HasRva { get diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs index 60ea543a3ff22..482e4243b8c97 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NoMetadataFieldLayoutAlgorithm.cs @@ -19,7 +19,7 @@ internal class NoMetadataFieldLayoutAlgorithm : FieldLayoutAlgorithm #endif private static NativeLayoutFieldAlgorithm s_nativeLayoutFieldAlgorithm = new NativeLayoutFieldAlgorithm(); - public unsafe override bool ComputeContainsGCPointers(DefType type) + public override unsafe bool ComputeContainsGCPointers(DefType type) { return type.RuntimeTypeHandle.ToEETypePtr()->HasGCPointers; } @@ -28,7 +28,7 @@ public unsafe override bool ComputeContainsGCPointers(DefType type) /// Reads the minimal information about type layout encoded in the /// MethodTable. That doesn't include field information. /// - public unsafe override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) + public override unsafe ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) { // If we need the field information, delegate to the native layout algorithm or metadata algorithm if (layoutKind != InstanceLayoutKind.TypeOnly) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index 9c1c186f66e86..ab1bbfba737a4 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -88,7 +88,7 @@ public TypeBuilder() /// The StaticClassConstructionContext for a type is encoded in the negative space /// of the NonGCStatic fields of a type. /// - public static unsafe readonly int ClassConstructorOffset = -sizeof(System.Runtime.CompilerServices.StaticClassConstructionContext); + public static readonly unsafe int ClassConstructorOffset = -sizeof(System.Runtime.CompilerServices.StaticClassConstructionContext); private LowLevelList _typesThatNeedTypeHandles = new LowLevelList(); @@ -105,6 +105,10 @@ public TypeBuilder() // Helper exception to abort type building if we do not find the generic type template internal class MissingTemplateException : Exception { + public MissingTemplateException() + // Cannot afford calling into resource manager from here, even to get the default message for System.Exception. + // This exception is always caught and rethrown as something more user friendly. + : base("Template is missing") { } } @@ -262,10 +266,8 @@ internal void PrepareType(TypeDesc type) bool noExtraPreparation = false; // Set this to true for types which don't need other types to be prepared. I.e GenericTypeDefinitions - if (type is DefType) + if (type is DefType typeAsDefType) { - DefType typeAsDefType = (DefType)type; - if (typeAsDefType.HasInstantiation) { if (typeAsDefType.IsTypeDefinition) @@ -301,10 +303,8 @@ internal void PrepareType(TypeDesc type) { PrepareType(((ParameterizedType)type).ParameterType); - if (type is ArrayType) + if (type is ArrayType typeAsArrayType) { - ArrayType typeAsArrayType = (ArrayType)type; - if (typeAsArrayType.IsSzArray && !typeAsArrayType.ElementType.IsPointer) { TypeDesc.ComputeTemplate(state); @@ -1322,10 +1322,8 @@ private void FinishRuntimeType(TypeDesc type) var state = type.GetTypeBuilderState(); - if (type is DefType) + if (type is DefType typeAsDefType) { - DefType typeAsDefType = (DefType)type; - if (type.HasInstantiation) { // Type definitions don't need any further finishing once created by the EETypeCreator @@ -1363,10 +1361,8 @@ private void FinishRuntimeType(TypeDesc type) } else if (type is ParameterizedType) { - if (type is ArrayType) + if (type is ArrayType typeAsSzArrayType) { - ArrayType typeAsSzArrayType = (ArrayType)type; - state.HalfBakedRuntimeTypeHandle.SetRelatedParameterType(GetRuntimeTypeHandle(typeAsSzArrayType.ElementType)); state.HalfBakedRuntimeTypeHandle.SetComponentSize(state.ComponentSize.Value); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs index 85037bae3fa1e..dcc81310178d8 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilderState.cs @@ -973,10 +973,8 @@ public int? FieldAlignment { return checked((ushort)((DefType)TypeBeingBuilt).InstanceFieldAlignment.AsInt); } - else if (TypeBeingBuilt is ArrayType) + else if (TypeBeingBuilt is ArrayType arrayType) { - ArrayType arrayType = (ArrayType)TypeBeingBuilt; - if (arrayType.ElementType is DefType) { return checked((ushort)((DefType)arrayType.ElementType).InstanceFieldAlignment.AsInt); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs index 1c1da35553b88..5083a87002d38 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs @@ -100,9 +100,8 @@ public RuntimeFieldHandleKey(RuntimeTypeHandle declaringType, string fieldName) public override bool Equals(object obj) { - if (obj is RuntimeFieldHandleKey) + if (obj is RuntimeFieldHandleKey other) { - RuntimeFieldHandleKey other = (RuntimeFieldHandleKey)obj; return Equals(other); } return false; @@ -145,9 +144,8 @@ public RuntimeMethodHandleKey(RuntimeTypeHandle declaringType, string methodName public override bool Equals(object obj) { - if (obj is RuntimeMethodHandleKey) + if (obj is RuntimeMethodHandleKey other) { - RuntimeMethodHandleKey other = (RuntimeMethodHandleKey)obj; return Equals(other); } return false; @@ -209,7 +207,7 @@ public unsafe RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeH fieldData->FieldName = fieldName; // Special flag (lowest bit set) in the handle value to indicate it was dynamically allocated - runtimeFieldHandleValue = runtimeFieldHandleValue + 1; + runtimeFieldHandleValue++; runtimeFieldHandle = *(RuntimeFieldHandle*)&runtimeFieldHandleValue; _runtimeFieldHandles.Add(key, runtimeFieldHandle); @@ -232,7 +230,7 @@ private unsafe bool TryGetDynamicRuntimeFieldHandleComponents(RuntimeFieldHandle // Special flag in the handle value to indicate it was dynamically allocated Debug.Assert((runtimeFieldHandleValue.ToInt64() & 0x1) == 0x1); - runtimeFieldHandleValue = runtimeFieldHandleValue - 1; + runtimeFieldHandleValue--; DynamicFieldHandleInfo* fieldData = (DynamicFieldHandleInfo*)runtimeFieldHandleValue.ToPointer(); declaringTypeHandle = *(RuntimeTypeHandle*)&(fieldData->DeclaringType); @@ -317,7 +315,7 @@ public unsafe RuntimeMethodHandle GetRuntimeMethodHandleForComponents(RuntimeTyp } // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob - runtimeMethodHandleValue = runtimeMethodHandleValue + 1; + runtimeMethodHandleValue++; runtimeMethodHandle = * (RuntimeMethodHandle*)&runtimeMethodHandleValue; _runtimeMethodHandles.Add(key, runtimeMethodHandle); @@ -344,7 +342,7 @@ private unsafe bool TryGetDynamicRuntimeMethodHandleComponents(RuntimeMethodHand Debug.Assert((runtimeMethodHandleValue.ToInt64() & 0x1) == 0x1); // Special flag in the handle value to indicate it was dynamically allocated, and doesn't point into the InvokeMap blob - runtimeMethodHandleValue = runtimeMethodHandleValue - 1; + runtimeMethodHandleValue--; DynamicMethodHandleInfo* methodData = (DynamicMethodHandleInfo*)runtimeMethodHandleValue.ToPointer(); declaringTypeHandle = *(RuntimeTypeHandle*)&(methodData->DeclaringType); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs index a0c3379a3efb0..7c619907610f7 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs @@ -417,7 +417,7 @@ public static unsafe IntPtr TryGetStaticClassConstructionContext(RuntimeTypeHand // what we have now is the base address of the non-gc statics of the type // what we need is the cctor context, which is just before that - ptr = ptr - sizeof(System.Runtime.CompilerServices.StaticClassConstructionContext); + ptr -= sizeof(System.Runtime.CompilerServices.StaticClassConstructionContext); return (IntPtr)ptr; } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.NamedTypeLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.NamedTypeLookup.cs index 478a6faa10511..c8aec12bc11d8 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.NamedTypeLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.NamedTypeLookup.cs @@ -41,7 +41,7 @@ private class NamedTypeLookupResult private class NamedTypeRuntimeTypeHandleToMetadataHashtable : LockFreeReaderHashtable { - protected unsafe override int GetKeyHashCode(RuntimeTypeHandle key) + protected override unsafe int GetKeyHashCode(RuntimeTypeHandle key) { return (int)key.ToEETypePtr()->HashCode; } @@ -50,7 +50,7 @@ protected override bool CompareKeyToValue(RuntimeTypeHandle key, NamedTypeLookup return key.Equals(value.RuntimeTypeHandle); } - protected unsafe override int GetValueHashCode(NamedTypeLookupResult value) + protected override unsafe int GetValueHashCode(NamedTypeLookupResult value) { return value.RuntimeTypeHandleHashcode; } @@ -122,7 +122,7 @@ private static int _rotl(int value, int shift) return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); } - protected unsafe override int GetKeyHashCode(QTypeDefinition key) + protected override unsafe int GetKeyHashCode(QTypeDefinition key) { return key.Token.GetHashCode() ^ _rotl(key.Reader.GetHashCode(), 8); } @@ -132,7 +132,7 @@ protected override bool CompareKeyToValue(QTypeDefinition key, NamedTypeLookupRe key.Reader.Equals(value.QualifiedTypeDefinition.Reader); } - protected unsafe override int GetValueHashCode(NamedTypeLookupResult value) + protected override unsafe int GetValueHashCode(NamedTypeLookupResult value) { return value.QualifiedTypeDefinition.Token.GetHashCode() ^ _rotl(value.QualifiedTypeDefinition.Reader.GetHashCode(), 8); } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.SignatureParsing.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.SignatureParsing.cs index 06a7ade1eaa85..4d13dbf569eb1 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.SignatureParsing.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.SignatureParsing.cs @@ -479,7 +479,7 @@ private bool TypeSignatureHasVarsNeedingCallingConventionConverter(ref NativePar for (uint i = 0; i < data; i++) result = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.NotParameter) || result; - if ((result == true) && (investigationLevel == HasVarsInvestigationLevel.Parameter)) + if (result && (investigationLevel == HasVarsInvestigationLevel.Parameter)) { if (!TryComputeHasInstantiationDeterminedSize(genericTypeDef, context, out result)) Environment.FailFast("Unable to setup calling convention converter correctly"); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs index 702baa4e22ecc..310534e09451c 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs @@ -25,6 +25,11 @@ namespace Internal.Runtime.TypeLoader { internal class Callbacks : TypeLoaderCallbacks { + public override TypeManagerHandle GetModuleForMetadataReader(MetadataReader reader) + { + return TypeLoaderEnvironment.Instance.ModuleList.GetModuleForMetadataReader(reader); + } + public override bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle) { return TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericTypeDefinitionHandle, genericTypeArgumentHandles, out runtimeTypeHandle); @@ -45,6 +50,11 @@ public override bool GetRuntimeMethodHandleComponents(RuntimeMethodHandle runtim return TypeLoaderEnvironment.Instance.TryGetRuntimeMethodHandleComponents(runtimeMethodHandle, out declaringTypeHandle, out nameAndSignature, out genericMethodArgs); } + public override RuntimeMethodHandle GetRuntimeMethodHandleForComponents(RuntimeTypeHandle declaringTypeHandle, string methodName, RuntimeSignature methodSignature, RuntimeTypeHandle[] genericMethodArgs) + { + return TypeLoaderEnvironment.Instance.GetRuntimeMethodHandleForComponents(declaringTypeHandle, methodName, methodSignature, genericMethodArgs); + } + public override bool CompareMethodSignatures(RuntimeSignature signature1, RuntimeSignature signature2) { return TypeLoaderEnvironment.Instance.CompareMethodSignatures(signature1, signature2); @@ -72,6 +82,11 @@ public override bool GetRuntimeFieldHandleComponents(RuntimeFieldHandle runtimeF return TypeLoaderEnvironment.Instance.TryGetRuntimeFieldHandleComponents(runtimeFieldHandle, out declaringTypeHandle, out fieldName); } + public override RuntimeFieldHandle GetRuntimeFieldHandleForComponents(RuntimeTypeHandle declaringTypeHandle, string fieldName) + { + return TypeLoaderEnvironment.Instance.GetRuntimeFieldHandleForComponents(declaringTypeHandle, fieldName); + } + public override IntPtr ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(IntPtr unboxingFunctionPointer, RuntimeTypeHandle declaringType) { return TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(unboxingFunctionPointer, declaringType); diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeDesc.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeDesc.Runtime.cs index 66cd911473ffa..09332e167c4b0 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeDesc.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeDesc.Runtime.cs @@ -84,10 +84,8 @@ internal bool RetrieveRuntimeTypeHandleIfPossible() if (state != null && state.AttemptedAndFailedToRetrieveTypeHandle) return false; - if (type is DefType) + if (type is DefType typeAsDefType) { - DefType typeAsDefType = (DefType)type; - TypeDesc typeDefinition = typeAsDefType.GetTypeDefinition(); RuntimeTypeHandle typeDefHandle = typeDefinition.RuntimeTypeHandle; if (typeDefHandle.IsNull()) @@ -155,10 +153,8 @@ internal bool RetrieveRuntimeTypeHandleIfPossible() } } } - else if (type is ParameterizedType) + else if (type is ParameterizedType typeAsParameterType) { - ParameterizedType typeAsParameterType = (ParameterizedType)type; - if (typeAsParameterType.ParameterType.RetrieveRuntimeTypeHandleIfPossible()) { RuntimeTypeHandle rtth; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs index 55923303d641e..1f2b9cd01f000 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs @@ -321,10 +321,8 @@ protected override int GetValueHashCode(MethodDesc value) protected override bool CompareKeyToValue(RuntimeMethodKey key, MethodDesc value) { - if (value is RuntimeMethodDesc) + if (value is RuntimeMethodDesc runtimeMethod) { - RuntimeMethodDesc runtimeMethod = (RuntimeMethodDesc)value; - if (key._unboxingStub != runtimeMethod.UnboxingStub) return false; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj index 73332581e5025..b9532d1de4c51 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj @@ -270,7 +270,6 @@ - @@ -281,7 +280,6 @@ - @@ -328,8 +326,6 @@ - - System\Runtime\CompilerServices\__BlockAllReflectionAttribute.cs diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeImports.cs index b6901b1ce50c3..b1ffb46e39c9b 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -73,20 +73,20 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe // [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewObject")] - private static unsafe extern object RhNewObject(MethodTable* pEEType); + private static extern unsafe object RhNewObject(MethodTable* pEEType); internal static unsafe object RhNewObject(EETypePtr pEEType) => RhNewObject(pEEType.ToPointer()); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhNewArray")] - private static unsafe extern Array RhNewArray(MethodTable* pEEType, int length); + private static extern unsafe Array RhNewArray(MethodTable* pEEType, int length); internal static unsafe Array RhNewArray(EETypePtr pEEType, int length) => RhNewArray(pEEType.ToPointer(), length); [DllImport(RuntimeLibrary)] - internal static unsafe extern void RhAllocateNewObject(IntPtr pEEType, uint flags, void* pResult); + internal static extern unsafe void RhAllocateNewObject(IntPtr pEEType, uint flags, void* pResult); [MethodImpl(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhpFallbackFailFast")] diff --git a/src/coreclr/nativeaot/docs/optimizing.md b/src/coreclr/nativeaot/docs/optimizing.md index aeee66fa2f41d..cc31c98df1539 100644 --- a/src/coreclr/nativeaot/docs/optimizing.md +++ b/src/coreclr/nativeaot/docs/optimizing.md @@ -12,12 +12,6 @@ To specify a switch, add a new property to your project file with one or more of under the `` node of your project file. -## Options related to library features - -Native AOT supports enabling and disabling all [documented framework library features](https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming-options#trimming-framework-library-features). For example, to remove globalization specific code and data, add a `true` property to your project. Disabling a framework feature (or enabling a minimal mode of the feature) can result in significant size savings. - -🛈 Native AOT difference: The `EnableUnsafeBinaryFormatterSerialization` framework switch is already set to the optimal value of `false` (removing the support for [obsolete](https://github.com/dotnet/designs/blob/21b274dbc21e4ae54b7e4c5dbd5ef31e439e78db/accepted/2020/better-obsoletion/binaryformatter-obsoletion.md) binary serialization). - ## Options related to trimming The Native AOT compiler supports the [documented options](https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-self-contained) for removing unused code (trimming). By default, the compiler tries to very conservatively remove some of the unused code. @@ -26,16 +20,21 @@ The Native AOT compiler supports the [documented options](https://docs.microsoft By default, the compiler tries to maximize compatibility with existing .NET code at the expense of compilation speed and size of the output executable. This allows people to use their existing code that worked well in a fully dynamic mode without hitting issues caused by trimming. To read more about reflection, see the [Reflection in AOT mode](reflection-in-aot-mode.md) document. -🛈 Native AOT difference: the `TrimMode` of framework assemblies is set to `link` by default. To compile entire framework assemblies, use `TrimmerRootAssembly` to root the selected assemblies. It's not recommended to root the entire framework. - -To enable more aggressive removal of unreferenced code, set the `` property to `link`. +To enable more aggressive removal of unreferenced code, set the `` property to `link`. To aid in troubleshooting some of the most common problems related to trimming add `true` to your project. This ensures types are preserved in their entirety, but the extra members that would otherwise be trimmed cannot be used in runtime reflection. This mode can turn some spurious `NullReferenceExceptions` (caused by reflection APIs returning a null) caused by trimming into more actionable exceptions. +The Native AOT compiler can remove unused metadata more effectively than non-Native deployment models. For example, it's possible to remove names and metadata for methods while keeping the native code of the method. The higher efficiency of trimming in Native AOT can result in differences in what's visible to reflection at runtime in trimming-unfriendly code. To increase compatibility with the less efficient non-Native trimming, set the `` property to `false`. This compatibility mode is not necessary if there are no trimming warnings. + +## Options related to library features + +Native AOT supports enabling and disabling all [documented framework library features](https://docs.microsoft.com/en-us/dotnet/core/deploying/trimming-options#trimming-framework-library-features). For example, to remove globalization specific code and data, add a `true` property to your project. Disabling a framework feature (or enabling a minimal mode of the feature) can result in significant size savings. + +Since `PublishTrimmed` is implied to be true with Native AOT, some framework features such as binary serialization are disabled by default. + ## Options related to metadata generation * `false`: this disables generation of stack trace metadata that provides textual names in stack traces. This is for example the text string one gets by calling `Exception.ToString()` on a caught exception. With this option disabled, stack traces will still be generated, but will be based on reflection metadata alone (they might be less complete). -* `true`: allows the compiler to remove reflection metadata from things that were not visible targets of reflection. By default, the compiler keeps metadata for everything that was compiled. With this option turned on, reflection metadata (and therefore reflection) will only be available for visible targets of reflection. Visible targets of reflection are things like assemblies rooted from the project file, RD.XML, ILLinkTrim descriptors, DynamicallyAccessedMembers annotations or DynamicDependency annotations. ## Options related to code generation * `Speed`: when generating optimized code, favor code execution speed. diff --git a/src/coreclr/nativeaot/docs/reflection-free-mode.md b/src/coreclr/nativeaot/docs/reflection-free-mode.md index 644421e36c1f1..f4acb394c67c9 100644 --- a/src/coreclr/nativeaot/docs/reflection-free-mode.md +++ b/src/coreclr/nativeaot/docs/reflection-free-mode.md @@ -34,7 +34,7 @@ Think of: Reflection-free mode **supports a limited set of reflection APIs** that keep their expected semantics. * `typeof(SomeType)` will return a `System.Type` that can be compared with results of other `typeof` expressions or results of `Object.GetType()` calls. The patterns commonly used in perf optimizations of generic code (e.g. `typeof(T) == typeof(byte)`) will work fine, and so will `obj.GetType() == typeof(SomeType)`. -* Following APIs on `System.Type` work: `TypeHandle`, `UnderlyingSystemType`, `BaseType`, `IsByRefLike`, `IsValueType`, `GetTypeCode`, `GetHashCode`, `GetElementType`, `GetInterfaces`, `HasElementType`, `IsArray`, `IsByRef`, `IsPointer`, `IsPrimitive`. +* Following APIs on `System.Type` work: `TypeHandle`, `UnderlyingSystemType`, `BaseType`, `IsByRefLike`, `IsValueType`, `GetTypeCode`, `GetHashCode`, `GetElementType`, `GetInterfaces`, `HasElementType`, `IsArray`, `IsByRef`, `IsPointer`, `IsPrimitive`, `IsAssignableFrom`, `IsAssignableTo`, `IsInstanceOfType`. * `Activator.CreateInstance()` will work. The compiler statically analyzes and expands this to efficient code at compile time. No reflection is involved at runtime. * `Assembly.GetExecutingAssembly()` will return a `System.Reflection.Assembly` that can be compared with other runtime `Assembly` instances. This is mostly to make it possible to use the `NativeLibrary.SetDllImportResolver` API. diff --git a/src/coreclr/nativeaot/nativeaot.sln b/src/coreclr/nativeaot/nativeaot.sln index f2bbfe6e9fb4a..7812cd25d4925 100644 --- a/src/coreclr/nativeaot/nativeaot.sln +++ b/src/coreclr/nativeaot/nativeaot.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.DisabledReflection", "System.Private.DisabledReflection\src\System.Private.DisabledReflection.csproj", "{ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.Core", "System.Private.Reflection.Core\src\System.Private.Reflection.Core.csproj", "{6147AF1A-5054-492A-9309-FA868A184414}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.Execution", "System.Private.Reflection.Execution\src\System.Private.Reflection.Execution.csproj", "{7498DD7C-76C1-4912-AF72-DA84E05B568F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.StackTraceMetadata", "System.Private.StackTraceMetadata\src\System.Private.StackTraceMetadata.csproj", "{33CAE331-16EE-443C-A0CC-4337B94A02AD}" diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index db7d114b5e879..dd7e99c665b10 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -96,6 +96,8 @@ typedef PVOID NATIVE_LIBRARY_HANDLE; #define _M_LOONGARCH64 1 #elif defined(__s390x__) && !defined(_M_S390X) #define _M_S390X 1 +#elif defined(__powerpc__) && !defined(_M_PPC64) +#define _M_PPC64 1 #endif #if defined(_M_IX86) && !defined(HOST_X86) @@ -110,6 +112,8 @@ typedef PVOID NATIVE_LIBRARY_HANDLE; #define HOST_LOONGARCH64 #elif defined(_M_S390X) && !defined(HOST_S390X) #define HOST_S390X +#elif defined(_M_PPC64) && !defined(HOST_POWERPC64) +#define HOST_POWERPC64 #endif #endif // !_MSC_VER @@ -2399,6 +2403,153 @@ typedef struct _KNONVOLATILE_CONTEXT_POINTERS { } KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; +#elif defined(HOST_POWERPC64) + +// There is no context for ppc64le defined in winnt.h, +// so we re-use the amd64 values. +#define CONTEXT_PPC64 0x100000 + +#define CONTEXT_CONTROL (CONTEXT_PPC64 | 0x1L) +#define CONTEXT_INTEGER (CONTEXT_PPC64 | 0x2L) +#define CONTEXT_FLOATING_POINT (CONTEXT_PPC64 | 0x4L) + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) + +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) + +#define CONTEXT_EXCEPTION_ACTIVE 0x8000000 +#define CONTEXT_SERVICE_ACTIVE 0x10000000 +#define CONTEXT_EXCEPTION_REQUEST 0x40000000 +#define CONTEXT_EXCEPTION_REPORTING 0x80000000 + +typedef struct DECLSPEC_ALIGN(16) _CONTEXT { + + // + // Control flags. + // + + DWORD ContextFlags; + + // + // Integer Registers + // + + DWORD64 R0; + DWORD64 R1; + DWORD64 R2; + DWORD64 R3; + DWORD64 R4; + DWORD64 R5; + DWORD64 R6; + DWORD64 R7; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 R16; + DWORD64 R17; + DWORD64 R18; + DWORD64 R19; + DWORD64 R20; + DWORD64 R21; + DWORD64 R22; + DWORD64 R23; + DWORD64 R24; + DWORD64 R25; + DWORD64 R26; + DWORD64 R27; + DWORD64 R28; + DWORD64 R29; + DWORD64 R30; + DWORD64 R31; + + // + // Floaring Point Registers + // + + DWORD64 F0; + DWORD64 F1; + DWORD64 F2; + DWORD64 F3; + DWORD64 F4; + DWORD64 F5; + DWORD64 F6; + DWORD64 F7; + DWORD64 F8; + DWORD64 F9; + DWORD64 F10; + DWORD64 F11; + DWORD64 F12; + DWORD64 F13; + DWORD64 F14; + DWORD64 F15; + DWORD64 F16; + DWORD64 F17; + DWORD64 F18; + DWORD64 F19; + DWORD64 F20; + DWORD64 F21; + DWORD64 F22; + DWORD64 F23; + DWORD64 F24; + DWORD64 F25; + DWORD64 F26; + DWORD64 F27; + DWORD64 F28; + DWORD64 F29; + DWORD64 F30; + DWORD64 F31; + DWORD64 Fpscr; + + // + // Control Registers + // + + DWORD64 Nip; + DWORD64 Msr; + DWORD64 Ctr; + DWORD64 Link; + + DWORD Xer; + DWORD Ccr; + + +} CONTEXT, *PCONTEXT, *LPCONTEXT; + +// +// Nonvolatile context pointer record. +// + +typedef struct _KNONVOLATILE_CONTEXT_POINTERS { + PDWORD64 R14; + PDWORD64 R15; + PDWORD64 R16; + PDWORD64 R17; + PDWORD64 R18; + PDWORD64 R19; + PDWORD64 R20; + PDWORD64 R21; + PDWORD64 R22; + PDWORD64 R23; + PDWORD64 R24; + PDWORD64 R25; + PDWORD64 R26; + PDWORD64 R27; + PDWORD64 R28; + PDWORD64 R29; + PDWORD64 R30; + PDWORD64 R31; + + // + // Need to add Floating point non-volatile registers. + // + +} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS; + #else #error Unknown architecture for defining CONTEXT. #endif @@ -2536,6 +2687,8 @@ PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_ #define PAL_CS_NATIVE_DATA_SIZE 96 #elif defined(__linux__) && defined(HOST_S390X) #define PAL_CS_NATIVE_DATA_SIZE 96 +#elif defined(__linux__) && defined(HOST_POWERPC64) +#define PAL_CS_NATIVE_DATA_SIZE 96 #elif defined(__NetBSD__) && defined(__amd64__) #define PAL_CS_NATIVE_DATA_SIZE 96 #elif defined(__NetBSD__) && defined(__earm__) diff --git a/src/coreclr/pal/inc/pal_endian.h b/src/coreclr/pal/inc/pal_endian.h index 6822b004ddaaf..43a8167562eee 100644 --- a/src/coreclr/pal/inc/pal_endian.h +++ b/src/coreclr/pal/inc/pal_endian.h @@ -16,7 +16,7 @@ extern "C++" { inline UINT16 SWAP16(UINT16 x) { - return (x >> 8) | (x << 8); + return (UINT16)((x >> 8) | (x << 8)); } inline UINT32 SWAP32(UINT32 x) diff --git a/src/coreclr/pal/inc/rt/intsafe.h b/src/coreclr/pal/inc/rt/intsafe.h deleted file mode 100644 index d793d357a3ba3..0000000000000 --- a/src/coreclr/pal/inc/rt/intsafe.h +++ /dev/null @@ -1,1401 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************** -* * -* intsafe.h -- This module defines helper functions to prevent * -* integer overflow issues. * -* * -* * -******************************************************************/ -#ifndef _INTSAFE_H_INCLUDED_ -#define _INTSAFE_H_INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include // for IN, etc. - -#define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW - -#ifndef LOWORD -#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff)) -#endif - -#ifndef HIWORD -#define HIWORD(l) ((WORD)(((DWORD_PTR)(l)) >> 16)) -#endif - -#define HIDWORD(_qw) ((ULONG)((_qw) >> 32)) -#define LODWORD(_qw) ((ULONG)(_qw)) - -#if defined(MIDL_PASS) || defined(RC_INVOKED) || defined(_M_CEE_PURE) \ - || defined(_M_AMD64) || defined(__ARM_ARCH) || defined(_M_S390X) || defined(_M_LOONGARCH64) - -#ifndef UInt32x32To64 -#define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b))) -#endif - -#elif defined(_M_IX86) - -#ifndef UInt32x32To64 -#define UInt32x32To64(a, b) (unsigned __int64)((unsigned __int64)(ULONG)(a) * (ULONG)(b)) -#endif - -#else - -#error Must define a target architecture. - -#endif - -// -// It is common for -1 to be used as an error value for various types -// -#define USHORT_ERROR (0xffff) -#define INT_ERROR (-1) -#define LONG_ERROR (-1L) -#define UINT_ERROR (0xffffffff) -#define ULONG_ERROR (0xffffffffUL) -#ifdef _MSC_VER -#define ULONGLONG_ERROR (0xffffffffffffffffui64) -#define HIDWORD_MASK (0xffffffff00000000ui64) -#else // _MSC_VER -#define ULONGLONG_ERROR (0xffffffffffffffffULL) -#define HIDWORD_MASK (0xffffffff00000000ULL) -#endif // _MSC_VER -#ifdef HOST_64BIT -#define SIZET_ERROR ULONGLONG_ERROR -#else -#define SIZET_ERROR ULONG_ERROR -#endif - -// -// We make some assumptions about the sizes of various types. Let's be -// explicit about those assumptions and check them. -// -C_ASSERT(sizeof(unsigned short) == 2); -C_ASSERT(sizeof(unsigned int) == 4); -C_ASSERT(sizeof(ULONG) == 4); - -// -// INT -> signed char conversion -// -__inline -HRESULT -IntToSignedChar( - IN INT iOperand, - OUT signed char* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if ((iOperand >= -128) && (iOperand <= 127)) - { - *pch = (signed char)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// INT -> UCHAR conversion -// -__inline -HRESULT -IntToUChar( - IN INT iOperand, - OUT UCHAR* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if ((iOperand >= 0) && (iOperand <= 255)) - { - *pch = (UCHAR)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// LONG -> UCHAR conversion -// -__inline -HRESULT -LongToUChar( - IN LONG lOperand, - OUT UCHAR* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if ((lOperand >= 0) && (lOperand <= 255)) - { - *pch = (UCHAR)lOperand; - hr = S_OK; - } - - return hr; -} - -// -// __inline is not sufficient. __forceinline is necessary. -// If the function is not inlined and you link .objs compiled with different compiler switches, -// you get one or the other function arbitrarily chosen. -// -// INT -> CHAR conversion -// -__forceinline -HRESULT -IntToChar( - IN INT iOperand, - OUT CHAR* pch) -{ -#ifdef _CHAR_UNSIGNED - return IntToUChar(iOperand, (UCHAR*)pch); -#else - return IntToSignedChar(iOperand, (signed char*)pch); -#endif -} - -// -// INT -> USHORT conversion -// -__inline -HRESULT -IntToUShort( - IN INT iOperand, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pusResult = USHORT_ERROR; - - if ((iOperand >= 0) && (iOperand <= USHRT_MAX)) - { - *pusResult = (USHORT)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// INT -> UINT conversion -// -__inline -HRESULT -IntToUInt( - IN INT iOperand, - OUT UINT* puResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *puResult = UINT_ERROR; - - if (iOperand >= 0) - { - *puResult = (UINT)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// INT -> ULONG conversion -// -__inline -HRESULT -IntToULong( - IN INT iOperand, - OUT ULONG* pulResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pulResult = ULONG_ERROR; - - if (iOperand >= 0) - { - *pulResult = (ULONG)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// INT -> ULONGLONG conversion -// -__inline -HRESULT -IntToULongLong( - IN INT iOperand, - OUT ULONGLONG* pullResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pullResult = ULONG_ERROR; - - if (iOperand >= 0) - { - *pullResult = (ULONGLONG)iOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT -> signed char conversion -// -__inline -HRESULT -UIntToSignedChar( - IN UINT uOperand, - OUT signed char* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if (uOperand <= 127) - { - *pch = (signed char)uOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT -> UCHAR conversion -// -__inline -HRESULT -UIntToUChar( - IN UINT uOperand, - OUT UCHAR* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if (uOperand <= 255) - { - *pch = (UCHAR)uOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT -> BYTE conversion -// -#define UIntToByte UIntToUChar - -// -// __inline is not sufficient. __forceinline is necessary. -// If the function is not inlined and you link .objs compiled with different compiler switches, -// you get one or the other function arbitrarily chosen. -// -// UINT -> CHAR conversion -// -__forceinline -HRESULT -UIntToChar( - IN UINT uOperand, - OUT CHAR* pch) -{ -#ifdef _CHAR_UNSIGNED - return UIntToUChar(uOperand, (UCHAR*)pch); -#else - return UIntToSignedChar(uOperand, (signed char*)pch); -#endif // _CHAR_UNSIGNED -} - -// -// UINT -> INT conversion -// -__inline -HRESULT -UIntToInt( - IN UINT uOperand, - OUT INT* piResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *piResult = INT_ERROR; - - if (uOperand <= INT_MAX) - { - *piResult = (INT)uOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT -> LONG conversion -// -__inline -HRESULT -UIntToLong( - IN UINT Operand, - OUT LONG* Result) -{ - if (Operand <= _I32_MAX) - { - *Result = (LONG)Operand; - return S_OK; - } - else - { - *Result = LONG_ERROR; - return INTSAFE_E_ARITHMETIC_OVERFLOW; - } -} - -// -// UINT -> ULONG conversion -// -__inline -HRESULT -UIntToULong( - IN UINT uOperand, - OUT ULONG* pulResult) -{ - *pulResult = (ULONG)uOperand; - - return S_OK; -} - -// -// ULONG -> UCHAR conversion -// -__inline -HRESULT -ULongToSignedChar( - IN ULONG ulOperand, - OUT signed char* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if (ulOperand <= 127) - { - *pch = (signed char)ulOperand; - hr = S_OK; - } - - return hr; -} - -// -// ULONG -> UCHAR conversion -// -__inline -HRESULT -ULongToUChar( - IN ULONG ulOperand, - OUT unsigned char* pch) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pch = 0; - - if (ulOperand <= 255) - { - *pch = (unsigned char)ulOperand; - hr = S_OK; - } - - return hr; -} - -// -// __inline is not sufficient. __forceinline is necessary. -// If the function is not inlined and you link .objs compiled with different compiler switches, -// you get one or the other function arbitrarily chosen. -// -// ULONG -> CHAR conversion -// -__forceinline -HRESULT -ULongToChar( - IN ULONG ulOperand, - OUT CHAR* pch) -{ -#ifdef _CHAR_UNSIGNED - return ULongToUChar(ulOperand, (unsigned char*)pch); -#else - return ULongToSignedChar(ulOperand, (signed char*)pch); -#endif // _CHAR_UNSIGNED -} - -// -// ULONG -> USHORT conversion -// -__inline -HRESULT -ULongToUShort( - IN ULONG ulOperand, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pusResult = USHORT_ERROR; - - if (ulOperand <= USHRT_MAX) - { - *pusResult = (USHORT)ulOperand; - hr = S_OK; - } - - return hr; -} - -// -// ULONG -> INT conversion -// -__inline -HRESULT -ULongToInt( - IN ULONG ulOperand, - OUT INT* piResult) -{ - if (ulOperand <= INT_MAX) - { - *piResult = (INT)ulOperand; - return S_OK; - } - else - { - *piResult = INT_ERROR; - return INTSAFE_E_ARITHMETIC_OVERFLOW; - } -} - -// -// ULONG -> UINT conversion -// -__inline -HRESULT -ULongToUInt( - IN ULONG ulOperand, - OUT UINT* puResult) -{ - *puResult = (UINT)ulOperand; - - return S_OK; -} - -// -// ULONG -> LONG conversion -// -__inline -HRESULT -ULongToLong( - IN ULONG Operand, - OUT LONG* Result) -{ - if (Operand <= _I32_MAX) - { - *Result = (LONG)Operand; - return S_OK; - } - else - { - *Result = LONG_ERROR; - return INTSAFE_E_ARITHMETIC_OVERFLOW; - } -} - -// -// ULONGLONG -> INT conversion -// -__inline -HRESULT -ULongLongToInt( - IN ULONGLONG ullOperand, - OUT INT* piResult) -{ - if (ullOperand <= INT_MAX) - { - *piResult = (INT)ullOperand; - return S_OK; - } - else - { - *piResult = INT_ERROR; - return INTSAFE_E_ARITHMETIC_OVERFLOW; - } -} - -// -// ULONGLONG -> LONG conversion -// -__inline -HRESULT -ULongLongToLong( - IN ULONGLONG Operand, - OUT LONG* Result) -{ - if (Operand <= _I32_MAX) - { - *Result = (LONG)Operand; - return S_OK; - } - else - { - *Result = LONG_ERROR; - return INTSAFE_E_ARITHMETIC_OVERFLOW; - } -} - -// -// UINT -> USHORT conversion -// -__inline -HRESULT -UIntToUShort( - IN UINT uOperand, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pusResult = USHORT_ERROR; - - if (uOperand <= USHRT_MAX) - { - *pusResult = (USHORT)uOperand; - hr = S_OK; - } - - return hr; -} - -// -// ULONGLONG -> USHORT conversion -// -__inline -HRESULT -ULongLongToUShort( - IN ULONGLONG ullOperand, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - USHORT usResult = USHORT_ERROR; - - if (ullOperand <= USHRT_MAX) - { - usResult = (USHORT)ullOperand; - hr = S_OK; - } - *pusResult = usResult; - - return hr; -} - -// -// ULONGLONG -> ULONG conversion -// -__inline -HRESULT -ULongLongToULong( - IN ULONGLONG ullOperand, - OUT ULONG* pulResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pulResult = ULONG_ERROR; - - if (ullOperand <= _UI32_MAX) - { - *pulResult = (ULONG)ullOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT_PTR -> ULONG conversion -// ULONG_PTR -> ULONG conversion -// -#ifdef HOST_64BIT - -#define UIntPtrToULong ULongLongToULong -#define ULongPtrToULong ULongLongToULong - -#else - -__inline -HRESULT -UIntPtrToULong( - IN UINT_PTR Operand, - OUT ULONG* pResult) -{ - *pResult = (ULONG)Operand; - return S_OK; -} - -__inline -HRESULT -ULongPtrToULong( - IN ULONG_PTR Operand, - OUT ULONG* pResult) -{ - *pResult = (ULONG)Operand; - return S_OK; -} - -#endif - -// -// ULONGLONG -> UINT conversion -// -__inline -HRESULT -ULongLongToUInt( - IN ULONGLONG ullOperand, - OUT UINT* puResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *puResult = UINT_ERROR; - - if (ullOperand <= UINT_MAX) - { - *puResult = (UINT)ullOperand; - hr = S_OK; - } - - return hr; -} - -// -// UINT_PTR -> UINT conversion -// ULONG_PTR -> UINT conversion -// -#ifdef HOST_64BIT - -#define UIntPtrToUInt ULongLongToUInt -#define ULongPtrToUInt ULongLongToUInt - -#else - -__inline -HRESULT -UIntPtrToUInt( - IN UINT_PTR Operand, - OUT UINT* pResult) -{ - *pResult = (UINT)Operand; - return S_OK; -} - -__inline -HRESULT -ULongPtrToUInt( - IN ULONG_PTR Operand, - OUT UINT* pResult) -{ - *pResult = (UINT)Operand; - return S_OK; -} - -#endif - -// -// * -> BYTE conversion (BYTE is always unsigned char) -// -#define IntToByte IntToUChar -#define UIntToByte UIntToUChar -#define LongToByte LongToUChar -#define ULongToByte ULongToUChar - -// -// * -> WORD conversion (WORD is always unsigned short) -// -#define IntToWord IntToUShort -#define LongToWord LongToUShort -#define LongLongToWord LongLongToUShort -#define UIntToWord UIntToUShort -#define ULongToWord ULongToUShort -#define ULongLongToWord ULongLongToUShort -#define UIntPtrToWord UIntPtrToUShort -#define ULongPtrToWord ULongPtrToUShort -#define SizeTToWord SizeTToUShort -#define SIZETToWord SIZETToUShort - -// -// WORD -> * conversion (WORD is always unsigned short) -// -#define WordToUChar UShortToUChar -#define WordToByte UShortToByte -#define WordToChar UShortToChar -#define WordToSignedChar UShortToSignedChar -#define WordToInt UShortToInt -#define WordToLong UShortToLong -#define WordToLongLong UShortToLongLong -#define WordToIntPtr UShortToIntPtr -#define WordToLongPtr UShortToLongPtr - -// -// * -> DWORD conversion (DWORD is always ULONG) -// -#define CharToDWord CharToULong -#define SignedCharToDWord SignedCharToULong -#define ShortToDWord ShortToULong -#define IntToDWord IntToULong -#define LongToDWord LongToULong -#define LongLongToDWord LongLongToULong -#define UIntToDWord UIntToULong -#define ULongLongToDWord ULongLongToULong -#define IntPtrToDWord IntPtrToULong -#define LongPtrToDWord LongPtrToULong -#define UIntPtrToDWord UIntPtrToULong -#define ULongPtrToDWord ULongPtrToULong -#define SizeTToDWord SizeTToULong -#define SIZETToDWord SIZETToULong - -// -// DWORD -> * conversion (DWORD is always ULONG) -// -#define DWordToChar ULongToChar -#define DWordToUChar ULongToUChar -#define DWordToByte ULongToByte -#define DWordToSignedChar ULongToSignedChar -#define DWordToUShort ULongToUShort -#define DWordToUInt ULongToUInt -#define DWordToInt ULongToInt -#define DWordToLong ULongToLong -#define DWordToLongLong ULongToLongLong -#define DWordToIntPtr ULongToIntPtr -#define DWordToLongPtr ULongToLongPtr - - -// -// * -> UINT_PTR conversion (UINT_PTR is UINT on Win32, ULONGLONG on Win64) -// -#ifdef HOST_64BIT -#define CharToUIntPtr CharToULongLong -#define SignedCharToUIntPtr SignedCharToULongLong -#define ShortToUIntPtr ShortToULongLong -#define IntToUIntPtr IntToULongLong -#define LongToUIntPtr LongToULongLong -#define LongLongToUIntPtr LongLongToULongLong -#define IntPtrToUIntPtr IntPtrToULongLong -#define LongPtrToUIntPtr LongPtrToULongLong -#else -#define CharToUIntPtr CharToUInt -#define SignedCharToUIntPtr SignedCharToUInt -#define ShortToUIntPtr ShortToUInt - -__inline -HRESULT -IntToUIntPtr( - IN INT iOperand, - OUT UINT_PTR* puResult) -{ - return IntToUInt(iOperand, (UINT*)puResult); -} - -#define LongToUIntPtr LongToUInt -#define LongLongToUIntPtr LongLongToUInt - -#define IntPtrToUIntPtr IntPtrToUInt -#define LongPtrToUIntPtr LongPtrToUInt -#endif - -__inline -HRESULT -ULongLongToUIntPtr( - IN ULONGLONG ullOperand, - OUT UINT_PTR* puResult) -{ -#ifdef HOST_64BIT - *puResult = ullOperand; - return S_OK; -#else - return ULongLongToUInt(ullOperand, (UINT*)puResult); -#endif -} - - -// -// UINT_PTR -> * conversion (UINT_PTR is UINT on Win32, ULONGLONG on Win64) -// -#ifdef HOST_64BIT -#define UIntPtrToUShort ULongLongToUShort -#define UIntPtrToInt ULongLongToInt -#define UIntPtrToLong ULongLongToLong -#define UIntPtrToLongLong ULongLongToLongLong -#define UIntPtrToIntPtr ULongLongToIntPtr -#define UIntPtrToLongPtr ULongLongToLongPtr -#else - -__inline -HRESULT -UIntPtrToUShort( - IN UINT_PTR uOperand, - OUT USHORT* pusResult) -{ - return UIntToUShort((UINT)uOperand, pusResult); -} - -__inline -HRESULT -UIntPtrToInt( - IN UINT_PTR uOperand, - OUT INT* piResult) -{ - return UIntToInt((UINT)uOperand, piResult); -} - -__inline -HRESULT -UIntPtrToLong( - IN UINT_PTR Operand, - OUT LONG* Result) -{ - return UIntToLong((UINT)Operand, Result); -} - -#define UIntPtrToLongLong UIntToLongLong -#define UIntPtrToIntPtr UIntToIntPtr -#define UIntPtrToLongPtr UIntToLongPtr -#endif - - -// -// * -> ULONG_PTR conversion (ULONG_PTR is ULONG on Win32, ULONGLONG on Win64) -// -#ifdef HOST_64BIT -#define CharToULongPtr CharToULongLong -#define SignedCharToULongPtr SignedCharToULongLong -#define ShortToULongPtr ShortToULongLong -#define IntToULongPtr IntToULongLong -#define LongToULongPtr LongToULongLong -#define LongLongToULongPtr LongLongToULongLong -#define IntPtrToULongPtr IntPtrToULongLong -#define LongPtrToULongPtr LongPtrToULongLong -#else -#define CharToULongPtr CharToULong -#define SignedCharToULongPtr SignedCharToULong -#define ShortToULongPtr ShortToULong - -__inline -HRESULT -IntToULongPtr( - IN INT iOperand, - OUT ULONG_PTR* pulResult) -{ - return IntToULong(iOperand, (ULONG*)pulResult); -} - -#define LongToULongPtr LongToULong -#define LongLongToULongPtr LongLongToULong - -#define IntPtrToULongPtr IntPtrToULong -#define LongPtrToULongPtr LongPtrToULong -#endif - -__inline -HRESULT -ULongLongToULongPtr( - IN ULONGLONG ullOperand, - OUT ULONG_PTR* pulResult) -{ -#ifdef HOST_64BIT - *pulResult = ullOperand; - return S_OK; -#else - return ULongLongToULong(ullOperand, (ULONG*)pulResult); -#endif -} - - -// -// ULONG_PTR -> * conversion (ULONG_PTR is ULONG on Win32, ULONGLONG on Win64) -// -#ifdef HOST_64BIT -#define ULongPtrToUShort ULongLongToUShort -#define ULongPtrToInt ULongLongToInt -#define ULongPtrToLong ULongLongToLong -#define ULongPtrToLongLong ULongLongToLongLong -#define ULongPtrToIntPtr ULongLongToIntPtr -#define ULongPtrToLongPtr ULongLongToLongPtr -#else - -__inline -HRESULT -ULongPtrToUShort( - IN ULONG_PTR ulOperand, - OUT USHORT* pusResult) -{ - return ULongToUShort((ULONG)ulOperand, pusResult); -} - -__inline -HRESULT -ULongPtrToInt( - IN ULONG_PTR ulOperand, - OUT INT* piResult) -{ - return ULongToInt((ULONG)ulOperand, piResult); -} - -__inline -HRESULT -ULongPtrToLong( - IN ULONG_PTR Operand, - OUT LONG* Result) -{ - return ULongToLong((ULONG)Operand, Result); -} - -#define ULongPtrToLongLong ULongToLongLong -#define ULongPtrToIntPtr ULongToIntPtr -#define ULongPtrToLongPtr ULongToLongPtr -#endif - -// -// * -> size_t conversion (size_t is always UINT_PTR) -// -#define CharToSizeT CharToUIntPtr -#define SignedCharToSizeT SignedCharToUIntPtr -#define ShortToSizeT ShortToUIntPtr -#define IntToSizeT IntToUIntPtr -#define LongToSizeT LongToUIntPtr -#define LongLongToSizeT LongLongToUIntPtr -#define ULongLongToSizeT ULongLongToUIntPtr -#define IntPtrToSizeT IntPtrToUIntPtr -#define LongPtrToSizeT LongPtrToUIntPtr - -// -// size_t -> * conversion (size_t is always UINT_PTR) -// -#define SizeTToUShort UIntPtrToUShort -#define SizeTToUInt UIntPtrToUInt -#define SizeTToULong UIntPtrToULong -#define SizeTToInt UIntPtrToInt -#define SizeTToLong UIntPtrToLong -#define SizeTToLongLong UIntPtrToLongLong -#define SizeTToIntPtr UIntPtrToIntPtr -#define SizeTToLongPtr UIntPtrToLongPtr - -// -// * -> SIZE_T conversion (SIZE_T is always ULONG_PTR) -// -#define CharToSIZET CharToULongPtr -#define SignedCharToSIZET SignedCharToULongPtr -#define ShortToSIZET ShortToULongPtr -#define IntToSIZET IntToULongPtr -#define LongToSIZET LongToULongPtr -#define LongLongToSIZET LongLongToULongPtr -#define IntPtrToSIZET IntPtrToULongPtr -#define LongPtrToSIZET LongPtrToULongPtr -#define ULongLongToSIZET ULongLongToULongPtr - -// -// SIZE_T -> * conversion (SIZE_T is always ULONG_PTR) -// -#define SIZETToUShort ULongPtrToUShort -#define SIZETToUInt ULongPtrToUInt -#define SIZETToULong ULongPtrToULong -#define SIZETToUIntPtr ULongPtrToUIntPtr -#define SIZETToULongPtr ULongPtrToULongPtr -#define SIZETToInt ULongPtrToInt -#define SIZETToLong ULongPtrToLong -#define SIZETToLongLong ULongPtrToLongLong -#define SIZETToIntPtr ULongPtrToIntPtr -#define SIZETToLongPtr ULongPtrToLongPtr - -// -// * -> DWORD_PTR conversion (DWORD_PTR is always ULONG_PTR) -// -#define CharToDWordPtr CharToULongPtr -#define SignedCharToDWordPtr SignedCharToULongPtr -#define ShortToDWordPtr ShortToULongPtr -#define IntToDWordPtr IntToULongPtr -#define LongToDWordPtr LongToULongPtr -#define LongLongToDWordPtr LongLongToULongPtr -#define ULongLongToDWordPtr ULongLongToULongPtr -#define IntPtrToDWordPtr IntPtrToULongPtr -#define LongPtrToDWordPtr LongPtrToULongPtr - -// -// DWORD_PTR -> * conversion (DWORD_PTR is always ULONG_PTR) -// -#define DWordPtrToUShort ULongPtrToUShort -#define DWordPtrToUInt ULongPtrToUInt -#define DWordPtrToULong ULongPtrToULong -#define DWordPtrToDWord ULongPtrToDWord -#define DWordPtrToInt ULongPtrToInt -#define DWordPtrToLong ULongPtrToLong -#define DWordPtrToLongLong ULongPtrToLongLong -#define DWordPtrToIntPtr ULongPtrToIntPtr -#define DWordPtrToLongPtr ULongPtrToLongPtr - -// -// USHORT addition -// -__inline -HRESULT -UShortAdd( - IN USHORT usAugend, - IN USHORT usAddend, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pusResult = USHORT_ERROR; - - if (((USHORT)(usAugend + usAddend)) >= usAugend) - { - *pusResult = (usAugend + usAddend); - hr = S_OK; - } - - return hr; -} - -// -// WORD addtition -// -#define WordAdd UShortAdd - -// -// UINT addition -// -__inline -HRESULT -UIntAdd( - IN UINT uAugend, - IN UINT uAddend, - OUT UINT* puResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *puResult = UINT_ERROR; - - if ((uAugend + uAddend) >= uAugend) - { - *puResult = (uAugend + uAddend); - hr = S_OK; - } - - return hr; -} - -// -// UINT_PTR addition -// -#define UIntPtrAdd SizeTAdd - -// -// ULONG addition -// -__inline -HRESULT -ULongAdd( - IN ULONG ulAugend, - IN ULONG ulAddend, - OUT ULONG* pulResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pulResult = ULONG_ERROR; - - if ((ulAugend + ulAddend) >= ulAugend) - { - *pulResult = (ulAugend + ulAddend); - hr = S_OK; - } - - return hr; -} - -// -// ULONG_PTR addition -// -#ifdef HOST_64BIT -#define ULongPtrAdd ULongLongAdd -#else -__inline -HRESULT -ULongPtrAdd( - IN ULONG_PTR ulAugend, - IN ULONG_PTR ulAddend, - OUT ULONG_PTR* pulResult) -{ - return ULongAdd((ULONG)ulAugend, (ULONG)ulAddend, (ULONG*)pulResult); -} -#endif // HOST_64BIT - -// -// DWORD addition -// -#define DWordAdd ULongAdd - -// -// DWORD_PTR addition -// -#define DWordPtrAdd ULongPtrAdd - -// -// size_t addition -// -__inline -HRESULT -SizeTAdd( - IN size_t Augend, - IN size_t Addend, - OUT size_t* pResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pResult = SIZET_ERROR; - - if ((Augend + Addend) >= Augend) - { - *pResult = (Augend + Addend); - hr = S_OK; - } - - return hr; -} - -// -// SIZE_T addition -// -#define SIZETAdd ULongPtrAdd - -// -// ULONGLONG addition -// -__inline -HRESULT -ULongLongAdd( - IN ULONGLONG ullAugend, - IN ULONGLONG ullAddend, - OUT ULONGLONG* pullResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pullResult = ULONGLONG_ERROR; - - if ((ullAugend + ullAddend) >= ullAugend) - { - *pullResult = (ullAugend + ullAddend); - hr = S_OK; - } - - return hr; -} - -// -// USHORT subtraction -// -__inline -HRESULT -UShortSub( - IN USHORT usMinuend, - IN USHORT usSubtrahend, - OUT USHORT* pusResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pusResult = USHORT_ERROR; - - if (usMinuend >= usSubtrahend) - { - *pusResult = (usMinuend - usSubtrahend); - hr = S_OK; - } - - return hr; -} - -// -// WORD subtraction -// -#define WordSub UShortSub - - -// -// UINT subtraction -// -__inline -HRESULT -UIntSub( - IN UINT uMinuend, - IN UINT uSubtrahend, - OUT UINT* puResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *puResult = UINT_ERROR; - - if (uMinuend >= uSubtrahend) - { - *puResult = (uMinuend - uSubtrahend); - hr = S_OK; - } - - return hr; -} - -// -// UINT_PTR subtraction -// -#define UIntPtrSub SizeTSub - -// -// ULONG subtraction -// -__inline -HRESULT -ULongSub( - IN ULONG ulMinuend, - IN ULONG ulSubtrahend, - OUT ULONG* pulResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pulResult = ULONG_ERROR; - - if (ulMinuend >= ulSubtrahend) - { - *pulResult = (ulMinuend - ulSubtrahend); - hr = S_OK; - } - - return hr; -} - -// -// ULONG_PTR subtraction -// -#ifdef HOST_64BIT -#define ULongPtrSub ULongLongSub -#else -__inline -HRESULT -ULongPtrSub( - IN ULONG_PTR ulMinuend, - IN ULONG_PTR ulSubtrahend, - OUT ULONG_PTR* pulResult) -{ - return ULongSub((ULONG)ulMinuend, (ULONG)ulSubtrahend, (ULONG*)pulResult); -} -#endif // HOST_64BIT - - -// -// DWORD subtraction -// -#define DWordSub ULongSub - -// -// DWORD_PTR subtraction -// -#define DWordPtrSub ULongPtrSub - -// -// size_t subtraction -// -__inline -HRESULT -SizeTSub( - IN size_t Minuend, - IN size_t Subtrahend, - OUT size_t* pResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pResult = SIZET_ERROR; - - if (Minuend >= Subtrahend) - { - *pResult = (Minuend - Subtrahend); - hr = S_OK; - } - - return hr; -} - -// -// SIZE_T subtraction -// -#define SIZETSub ULongPtrSub - -// -// ULONGLONG subtraction -// -__inline -HRESULT -ULongLongSub( - IN ULONGLONG ullMinuend, - IN ULONGLONG ullSubtrahend, - OUT ULONGLONG* pullResult) -{ - HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; - *pullResult = ULONGLONG_ERROR; - - if (ullMinuend >= ullSubtrahend) - { - *pullResult = (ullMinuend - ullSubtrahend); - hr = S_OK; - } - - return hr; -} - -// -// USHORT multiplication -// -__inline -HRESULT -UShortMult( - IN USHORT usMultiplicand, - IN USHORT usMultiplier, - OUT USHORT* pusResult) -{ - ULONG ulResult = ((ULONG)usMultiplicand) * (ULONG)usMultiplier; - - return ULongToUShort(ulResult, pusResult); -} - -// -// WORD multiplication -// -#define WordMult UShortMult - -// -// UINT multiplication -// -__inline -HRESULT -UIntMult( - IN UINT uMultiplicand, - IN UINT uMultiplier, - OUT UINT* puResult) -{ - ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier); - - return ULongLongToUInt(ull64Result, puResult); -} - -// -// ULONG multiplication -// -__inline -HRESULT -ULongMult( - IN ULONG ulMultiplicand, - IN ULONG ulMultiplier, - OUT ULONG* pulResult) -{ - ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier); - - return ULongLongToULong(ull64Result, pulResult); -} - -// -// DWORD multiplication -// -#define DWordMult ULongMult - -// -// DWORD_PTR multiplication -// -#define DWordPtrMult ULongPtrMult - -#endif // _INTSAFE_H_INCLUDED_ diff --git a/src/coreclr/pal/inc/rt/palrt.h b/src/coreclr/pal/inc/rt/palrt.h index 626422334ef69..10808247710ac 100644 --- a/src/coreclr/pal/inc/rt/palrt.h +++ b/src/coreclr/pal/inc/rt/palrt.h @@ -1148,6 +1148,14 @@ typedef struct _DISPATCHER_CONTEXT { DWORD Reserved; } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; +#elif defined(HOST_POWERPC64) + +typedef struct _DISPATCHER_CONTEXT { + // PPC64LE does not build the VM or JIT at this point, + // so we only provide a dummy definition. + DWORD Reserved; +} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; + #else #error Unknown architecture for defining DISPATCHER_CONTEXT. diff --git a/src/coreclr/pal/inc/unixasmmacros.inc b/src/coreclr/pal/inc/unixasmmacros.inc index a814c5ab98171..cf05fbe319934 100644 --- a/src/coreclr/pal/inc/unixasmmacros.inc +++ b/src/coreclr/pal/inc/unixasmmacros.inc @@ -19,7 +19,7 @@ #if defined(__APPLE__) #define C_PLTFUNC(name) _##name -#elif defined(HOST_ARM64) +#elif defined(HOST_ARM64) || defined(HOST_POWERPC64) #define C_PLTFUNC(name) name #else #define C_PLTFUNC(name) name@PLT @@ -47,4 +47,6 @@ #include "unixasmmacross390x.inc" #elif defined(HOST_LOONGARCH64) #include "unixasmmacrosloongarch64.inc" +#elif defined(HOST_POWERPC64) +#include "unixasmmacrosppc64le.inc" #endif diff --git a/src/coreclr/pal/inc/unixasmmacrosppc64le.inc b/src/coreclr/pal/inc/unixasmmacrosppc64le.inc new file mode 100644 index 0000000000000..2c1c4d6f3e1de --- /dev/null +++ b/src/coreclr/pal/inc/unixasmmacrosppc64le.inc @@ -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. + +.macro NESTED_ENTRY Name, Section, Handler + LEAF_ENTRY \Name, \Section + .ifnc \Handler, NoHandler + .personality C_FUNC(\Handler) + .endif +.endm + +.macro NESTED_END Name, Section + LEAF_END \Name, \Section +.endm + +.macro PATCH_LABEL Name + .global C_FUNC(\Name) +C_FUNC(\Name): +.endm + +.macro LEAF_ENTRY Name, Section + .global C_FUNC(\Name) + .type \Name, %function +C_FUNC(\Name): + .cfi_startproc +.endm + +.macro LEAF_END Name, Section + .size \Name, .-\Name + .cfi_endproc +.endm + +.macro LEAF_END_MARKED Name, Section +C_FUNC(\Name\()_End): + .global C_FUNC(\Name\()_End) + LEAF_END \Name, \Section +.endm + diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index 4e6509c88590c..933333aba64a2 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -56,6 +56,8 @@ elseif(CLR_CMAKE_HOST_ARCH_I386) set(PAL_ARCH_SOURCES_DIR i386) elseif(CLR_CMAKE_HOST_ARCH_S390X) set(PAL_ARCH_SOURCES_DIR s390x) +elseif(CLR_CMAKE_HOST_ARCH_POWERPC64) + set(PAL_ARCH_SOURCES_DIR ppc64le) endif() if(CLR_CMAKE_USE_SYSTEM_LIBUNWIND) diff --git a/src/coreclr/pal/src/arch/ppc64le/asmconstants.h b/src/coreclr/pal/src/arch/ppc64le/asmconstants.h new file mode 100644 index 0000000000000..15ee945dafaa4 --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/asmconstants.h @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __PAL_POWERPC_ASMCONSTANTS_H__ +#define __PAL_POWERPC_ASMCONSTANTS_H__ + +#define CONTEXT_PPC64 0x100000 + +#define CONTEXT_CONTROL 1 +#define CONTEXT_INTEGER 2 +#define CONTEXT_FLOATING_POINT 4 + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) + +#define CONTEXT_ContextFlags 0 +#define CONTEXT_R0 CONTEXT_ContextFlags+8 +#define CONTEXT_R1 CONTEXT_R0+8 +#define CONTEXT_R2 CONTEXT_R1+8 +#define CONTEXT_R3 CONTEXT_R2+8 +#define CONTEXT_R4 CONTEXT_R3+8 +#define CONTEXT_R5 CONTEXT_R4+8 +#define CONTEXT_R6 CONTEXT_R5+8 +#define CONTEXT_R7 CONTEXT_R6+8 +#define CONTEXT_R8 CONTEXT_R7+8 +#define CONTEXT_R9 CONTEXT_R8+8 +#define CONTEXT_R10 CONTEXT_R9+8 +#define CONTEXT_R11 CONTEXT_R10+8 +#define CONTEXT_R12 CONTEXT_R11+8 +#define CONTEXT_R13 CONTEXT_R12+8 +#define CONTEXT_R14 CONTEXT_R13+8 +#define CONTEXT_R15 CONTEXT_R14+8 +#define CONTEXT_R16 CONTEXT_R15+8 +#define CONTEXT_R17 CONTEXT_R16+8 +#define CONTEXT_R18 CONTEXT_R17+8 +#define CONTEXT_R19 CONTEXT_R18+8 +#define CONTEXT_R20 CONTEXT_R19+8 +#define CONTEXT_R21 CONTEXT_R20+8 +#define CONTEXT_R22 CONTEXT_R21+8 +#define CONTEXT_R23 CONTEXT_R22+8 +#define CONTEXT_R24 CONTEXT_R23+8 +#define CONTEXT_R25 CONTEXT_R24+8 +#define CONTEXT_R26 CONTEXT_R25+8 +#define CONTEXT_R27 CONTEXT_R26+8 +#define CONTEXT_R28 CONTEXT_R27+8 +#define CONTEXT_R29 CONTEXT_R28+8 +#define CONTEXT_R30 CONTEXT_R29+8 +#define CONTEXT_R31 CONTEXT_R30+8 +#define CONTEXT_F0 CONTEXT_R31+8 +#define CONTEXT_F1 CONTEXT_F0+8 +#define CONTEXT_F2 CONTEXT_F1+8 +#define CONTEXT_F3 CONTEXT_F2+8 +#define CONTEXT_F4 CONTEXT_F3+8 +#define CONTEXT_F5 CONTEXT_F4+8 +#define CONTEXT_F6 CONTEXT_F5+8 +#define CONTEXT_F7 CONTEXT_F6+8 +#define CONTEXT_F8 CONTEXT_F7+8 +#define CONTEXT_F9 CONTEXT_F8+8 +#define CONTEXT_F10 CONTEXT_F9+8 +#define CONTEXT_F11 CONTEXT_F10+8 +#define CONTEXT_F12 CONTEXT_F11+8 +#define CONTEXT_F13 CONTEXT_F12+8 +#define CONTEXT_F14 CONTEXT_F13+8 +#define CONTEXT_F15 CONTEXT_F14+8 +#define CONTEXT_F16 CONTEXT_F15+8 +#define CONTEXT_F17 CONTEXT_F16+8 +#define CONTEXT_F18 CONTEXT_F17+8 +#define CONTEXT_F19 CONTEXT_F18+8 +#define CONTEXT_F20 CONTEXT_F19+8 +#define CONTEXT_F21 CONTEXT_F20+8 +#define CONTEXT_F22 CONTEXT_F21+8 +#define CONTEXT_F23 CONTEXT_F22+8 +#define CONTEXT_F24 CONTEXT_F23+8 +#define CONTEXT_F25 CONTEXT_F24+8 +#define CONTEXT_F26 CONTEXT_F25+8 +#define CONTEXT_F27 CONTEXT_F26+8 +#define CONTEXT_F28 CONTEXT_F27+8 +#define CONTEXT_F29 CONTEXT_F28+8 +#define CONTEXT_F30 CONTEXT_F29+8 +#define CONTEXT_F31 CONTEXT_F30+8 +#define CONTEXT_FPSCR CONTEXT_F31+8 +#define CONTEXT_NIP CONTEXT_FPSCR+8 +#define CONTEXT_MSR CONTEXT_NIP+8 +#define CONTEXT_CTR CONTEXT_MSR+8 +#define CONTEXT_LINK CONTEXT_CTR+8 +#define CONTEXT_XER CONTEXT_LINK+8 +#define CONTEXT_CCR CONTEXT_XER+8 +#define CONTEXT_Size CONTEXT_CCR+8 + +#endif diff --git a/src/coreclr/pal/src/arch/ppc64le/callsignalhandlerwrapper.S b/src/coreclr/pal/src/arch/ppc64le/callsignalhandlerwrapper.S new file mode 100644 index 0000000000000..1ace1393c3feb --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/callsignalhandlerwrapper.S @@ -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. + +#include "unixasmmacros.inc" +#include "asmconstants.h" + +.macro CALL_SIGNAL_HANDLER_WRAPPER Alignment + +.globl C_FUNC(SignalHandlerWorkerReturnOffset\Alignment) +C_FUNC(SignalHandlerWorkerReturnOffset\Alignment): + .int LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment)-C_FUNC(CallSignalHandlerWrapper\Alignment) + +// This function is never called, only a fake stack frame will be setup to have a return +// address set to SignalHandlerWorkerReturn during SIGSEGV handling. +// It enables the unwinder to unwind stack from the handling code to the actual failure site. +NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler + mflr %r0 + std %r0, 16(%r1) + stdu %r1,-32(%r1) + bl EXTERNAL_C_FUNC(signal_handler_worker) +LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment): + addi %r1, %r1, 32 + ld %r0, 16(%r1) + mtlr %r0 + blr +NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT + +.endm + +CALL_SIGNAL_HANDLER_WRAPPER 0 +CALL_SIGNAL_HANDLER_WRAPPER 8 diff --git a/src/coreclr/pal/src/arch/ppc64le/context2.S b/src/coreclr/pal/src/arch/ppc64le/context2.S new file mode 100644 index 0000000000000..f48c7414ae6e6 --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/context2.S @@ -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. +// +// Implementation of _CONTEXT_CaptureContext for the IBM power ppc64le platform. +// This function is processor dependent. It is used by exception handling, +// and is always apply to the current thread. +// + +#include "unixasmmacros.inc" +#include "asmconstants.h" + +// Incoming: +// R3: Context* +// +LEAF_ENTRY CONTEXT_CaptureContext, _TEXT + + // Store all general purpose registers + std %r0, CONTEXT_R0(%r3) + std %r1, CONTEXT_R1(%r3) + std %r2, CONTEXT_R2(%r3) + std %r3, CONTEXT_R3(%r3) + std %r4, CONTEXT_R4(%r3) + std %r5, CONTEXT_R5(%r3) + std %r6, CONTEXT_R6(%r3) + std %r7, CONTEXT_R7(%r3) + std %r8, CONTEXT_R8(%r3) + std %r9, CONTEXT_R9(%r3) + std %r10, CONTEXT_R10(%r3) + std %r11, CONTEXT_R11(%r3) + std %r12, CONTEXT_R12(%r3) + std %r13, CONTEXT_R13(%r3) + std %r14, CONTEXT_R14(%r3) + std %r15, CONTEXT_R15(%r3) + std %r16, CONTEXT_R16(%r3) + std %r17, CONTEXT_R17(%r3) + std %r18, CONTEXT_R18(%r3) + std %r19, CONTEXT_R19(%r3) + std %r20, CONTEXT_R20(%r3) + std %r21, CONTEXT_R21(%r3) + std %r22, CONTEXT_R22(%r3) + std %r23, CONTEXT_R23(%r3) + std %r24, CONTEXT_R24(%r3) + std %r25, CONTEXT_R25(%r3) + std %r26, CONTEXT_R26(%r3) + std %r27, CONTEXT_R27(%r3) + std %r28, CONTEXT_R28(%r3) + std %r29, CONTEXT_R29(%r3) + std %r30, CONTEXT_R30(%r3) + std %r31, CONTEXT_R31(%r3) + + // Store all floating point registers + stfd %f0, CONTEXT_F0(%r3) + stfd %f1, CONTEXT_F1(%r3) + stfd %f2, CONTEXT_F2(%r3) + stfd %f3, CONTEXT_F3(%r3) + stfd %f4, CONTEXT_F4(%r3) + stfd %f5, CONTEXT_F5(%r3) + stfd %f6, CONTEXT_F6(%r3) + stfd %f7, CONTEXT_F7(%r3) + stfd %f8, CONTEXT_F8(%r3) + stfd %f9, CONTEXT_F9(%r3) + stfd %f10, CONTEXT_F10(%r3) + stfd %f11, CONTEXT_F11(%r3) + stfd %f12, CONTEXT_F12(%r3) + stfd %f13, CONTEXT_F13(%r3) + stfd %f14, CONTEXT_F14(%r3) + stfd %f15, CONTEXT_F15(%r3) + stfd %f16, CONTEXT_F16(%r3) + stfd %f17, CONTEXT_F17(%r3) + stfd %f18, CONTEXT_F18(%r3) + stfd %f19, CONTEXT_F19(%r3) + stfd %f20, CONTEXT_F20(%r3) + stfd %f21, CONTEXT_F21(%r3) + stfd %f22, CONTEXT_F22(%r3) + stfd %f23, CONTEXT_F23(%r3) + stfd %f24, CONTEXT_F24(%r3) + stfd %f25, CONTEXT_F25(%r3) + stfd %f26, CONTEXT_F26(%r3) + stfd %f27, CONTEXT_F27(%r3) + stfd %f28, CONTEXT_F28(%r3) + stfd %f29, CONTEXT_F29(%r3) + stfd %f30, CONTEXT_F30(%r3) + stfd %f31, CONTEXT_F31(%r3) + + // Save Control Registers - XER, LR and CTR + mfspr 5, 1 + std %r5, CONTEXT_XER(%r3) + mflr %r5 + std %r5, CONTEXT_LINK(%r3) + mfspr 5, 9 + std %r5, CONTEXT_CTR(%r3) + + // Restore r5 general purpose register + ld %r5, CONTEXT_R5(%r3) + + blr +LEAF_END CONTEXT_CaptureContext, _TEXT + +LEAF_ENTRY RtlCaptureContext, _TEXT + b C_FUNC(CONTEXT_CaptureContext) +LEAF_END RtlCaptureContext, _TEXT + +LEAF_ENTRY RtlRestoreContext, _TEXT + + // Restore all floating point registers + lfd %f0, CONTEXT_F0(%r3) + lfd %f1, CONTEXT_F1(%r3) + lfd %f2, CONTEXT_F2(%r3) + lfd %f3, CONTEXT_F3(%r3) + lfd %f4, CONTEXT_F4(%r3) + lfd %f5, CONTEXT_F5(%r3) + lfd %f6, CONTEXT_F6(%r3) + lfd %f7, CONTEXT_F7(%r3) + lfd %f8, CONTEXT_F8(%r3) + lfd %f9, CONTEXT_F9(%r3) + lfd %f10, CONTEXT_F10(%r3) + lfd %f11, CONTEXT_F11(%r3) + lfd %f12, CONTEXT_F12(%r3) + lfd %f13, CONTEXT_F13(%r3) + lfd %f14, CONTEXT_F14(%r3) + lfd %f15, CONTEXT_F15(%r3) + lfd %f16, CONTEXT_F16(%r3) + lfd %f17, CONTEXT_F17(%r3) + lfd %f18, CONTEXT_F18(%r3) + lfd %f19, CONTEXT_F19(%r3) + lfd %f20, CONTEXT_F20(%r3) + lfd %f21, CONTEXT_F21(%r3) + lfd %f22, CONTEXT_F22(%r3) + lfd %f23, CONTEXT_F23(%r3) + lfd %f24, CONTEXT_F24(%r3) + lfd %f25, CONTEXT_F25(%r3) + lfd %f26, CONTEXT_F26(%r3) + lfd %f27, CONTEXT_F27(%r3) + lfd %f28, CONTEXT_F28(%r3) + lfd %f29, CONTEXT_F29(%r3) + lfd %f30, CONTEXT_F30(%r3) + lfd %f31, CONTEXT_F31(%r3) + + // Restore all general purpose registers + ld %r0, CONTEXT_R0(%R3) + ld %r1, CONTEXT_R1(%r3) + ld %r2, CONTEXT_R2(%r3) + ld %r4, CONTEXT_R4(%r3) + ld %r5, CONTEXT_R5(%r3) + ld %r6, CONTEXT_R6(%r3) + ld %r7, CONTEXT_R7(%r3) + ld %r8, CONTEXT_R8(%r3) + ld %r9, CONTEXT_R9(%r3) + ld %r10, CONTEXT_R10(%r3) + ld %r11, CONTEXT_R11(%r3) + ld %r12, CONTEXT_R12(%r3) + ld %r13, CONTEXT_R13(%r3) + ld %r14, CONTEXT_R14(%r3) + ld %r15, CONTEXT_R15(%r3) + ld %r16, CONTEXT_R16(%r3) + ld %r17, CONTEXT_R17(%r3) + ld %r18, CONTEXT_R18(%r3) + ld %r19, CONTEXT_R19(%r3) + ld %r20, CONTEXT_R20(%r3) + ld %r21, CONTEXT_R21(%r3) + ld %r22, CONTEXT_R22(%r3) + ld %r23, CONTEXT_R23(%r3) + ld %r24, CONTEXT_R24(%r3) + ld %r25, CONTEXT_R25(%r3) + ld %r26, CONTEXT_R26(%r3) + ld %r27, CONTEXT_R27(%r3) + ld %r28, CONTEXT_R28(%r3) + ld %r29, CONTEXT_R29(%r3) + ld %r30, CONTEXT_R30(%r3) + ld %r31, CONTEXT_R31(%r3) + + // Restore Control Register - XER + ld %r12, CONTEXT_XER(%r3) + mtspr 1, 12 + + // Restore Control Register - LR + mtlr %r0 + + // Restore Control Register - CTR + ld %r12, CONTEXT_LINK(%r3) + mtctr %r12 + + // Restore R3 register + ld %r3, CONTEXT_R3(%r3) + + // Branch to CTR register location + bctr +LEAF_END RtlRestoreContext, _TEXT diff --git a/src/coreclr/pal/src/arch/ppc64le/debugbreak.S b/src/coreclr/pal/src/arch/ppc64le/debugbreak.S new file mode 100644 index 0000000000000..8ff9c9c40cf7c --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/debugbreak.S @@ -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. + +#include "unixasmmacros.inc" + +LEAF_ENTRY DBG_DebugBreak, _TEXT + bl abort + nop +LEAF_END_MARKED DBG_DebugBreak, _TEXT + diff --git a/src/coreclr/pal/src/arch/ppc64le/exceptionhelper.S b/src/coreclr/pal/src/arch/ppc64le/exceptionhelper.S new file mode 100644 index 0000000000000..9c3d9f4881aec --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/exceptionhelper.S @@ -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. + +#include "unixasmmacros.inc" +#include "asmconstants.h" + +////////////////////////////////////////////////////////////////////////// +// +// This function creates a stack frame right below the target frame, restores all callee +// saved registers from the passed in context, sets R15 to that frame and sets the +// return address to the target frame's PSW address. +// Then it uses the ThrowExceptionHelper to throw the passed in exception from that context. +// EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex); +LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT + + // Restore all non volatile floating point registers + lfd %f15, CONTEXT_F15(%r3) + lfd %f16, CONTEXT_F16(%r3) + lfd %f17, CONTEXT_F17(%r3) + lfd %f18, CONTEXT_F18(%r3) + lfd %f19, CONTEXT_F19(%r3) + lfd %f20, CONTEXT_F20(%r3) + lfd %f21, CONTEXT_F21(%r3) + lfd %f22, CONTEXT_F22(%r3) + lfd %f23, CONTEXT_F23(%r3) + lfd %f24, CONTEXT_F24(%r3) + lfd %f25, CONTEXT_F25(%r3) + lfd %f26, CONTEXT_F26(%r3) + lfd %f27, CONTEXT_F27(%r3) + lfd %f28, CONTEXT_F28(%r3) + lfd %f29, CONTEXT_F29(%r3) + lfd %f30, CONTEXT_F30(%r3) + lfd %f31, CONTEXT_F31(%r3) + + // Restore all non volatile general purpose registers + ld %r14, CONTEXT_R14(%r3) + ld %r15, CONTEXT_R15(%r3) + ld %r16, CONTEXT_R16(%r3) + ld %r17, CONTEXT_R17(%r3) + ld %r18, CONTEXT_R18(%r3) + ld %r19, CONTEXT_R19(%r3) + ld %r20, CONTEXT_R20(%r3) + ld %r21, CONTEXT_R21(%r3) + ld %r22, CONTEXT_R22(%r3) + ld %r23, CONTEXT_R23(%r3) + ld %r24, CONTEXT_R24(%r3) + ld %r25, CONTEXT_R25(%r3) + ld %r26, CONTEXT_R26(%r3) + ld %r27, CONTEXT_R27(%r3) + ld %r28, CONTEXT_R28(%r3) + ld %r29, CONTEXT_R29(%r3) + ld %r30, CONTEXT_R30(%r3) + ld %r31, CONTEXT_R31(%r3) + + ld %r0, CONTEXT_NIP(%r3) + mtlr %r0 + + ld %r1, CONTEXT_R1(%r3) + + // The PAL_SEHException pointer + mr %r3, %r4 + b EXTERNAL_C_FUNC(ThrowExceptionHelper) +LEAF_END ThrowExceptionFromContextInternal, _TEXT diff --git a/src/coreclr/pal/src/arch/ppc64le/processor.cpp b/src/coreclr/pal/src/arch/ppc64le/processor.cpp new file mode 100644 index 0000000000000..6680dbc532677 --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/processor.cpp @@ -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. + +/*++ + + + +Module Name: + + processor.cpp + +Abstract: + + Implementation of processor related functions for the IBM PowerPC (ppc64le) + platforms. These functions are processor dependent. + + + +--*/ + +#include "pal/palinternal.h" diff --git a/src/coreclr/pal/src/arch/ppc64le/signalhandlerhelper.cpp b/src/coreclr/pal/src/arch/ppc64le/signalhandlerhelper.cpp new file mode 100644 index 0000000000000..66615176a3ad4 --- /dev/null +++ b/src/coreclr/pal/src/arch/ppc64le/signalhandlerhelper.cpp @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal/dbgmsg.h" +SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first + +#include "pal/palinternal.h" +#include "pal/context.h" +#include "pal/signal.hpp" +#include "pal/utils.h" +#include + +/*++ +Function : + ExecuteHandlerOnCustomStack + + Execute signal handler on a custom stack, the current stack pointer is specified by the customSp + If the customSp is 0, then the handler is executed on the original stack where the signal was fired. + It installs a fake stack frame to enable stack unwinding to the signal source location. + +Parameters : + POSIX signal handler parameter list ("man sigaction" for details) + returnPoint - context to which the function returns if the common_signal_handler returns + + (no return value) +--*/ +void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t customSp, SignalHandlerWorkerReturnPoint* returnPoint) +{ + ucontext_t *ucontext = (ucontext_t *)context; + size_t faultSp = (size_t)MCREG_R1(ucontext->uc_mcontext); + _ASSERTE(IS_ALIGNED(faultSp, 8)); + + if (customSp == 0) + { + customSp = faultSp; + } + + size_t fakeFrameReturnAddress; + if (IS_ALIGNED(faultSp, 16)) + { + fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0; + } + else + { + fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8; + } + + // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction + size_t* saveArea = (size_t*)(customSp - 32); + saveArea[0] = faultSp; + saveArea[2] = (size_t)MCREG_Nip(ucontext->uc_mcontext); + size_t sp = customSp - 32; + + // Switch the current context to the signal_handler_worker and the custom stack + CONTEXT context2; + RtlCaptureContext(&context2); + + context2.Link = (size_t)signal_handler_worker; + context2.R0 = fakeFrameReturnAddress; + context2.R1 = sp; + context2.R3 = code; + context2.R4 = (size_t)siginfo; + context2.R5 = (size_t)context; + context2.R6 = (size_t)returnPoint; + + + RtlRestoreContext(&context2, NULL); +} diff --git a/src/coreclr/pal/src/cruntime/file.cpp b/src/coreclr/pal/src/cruntime/file.cpp index eb2512c68e0e3..70462122c10a2 100644 --- a/src/coreclr/pal/src/cruntime/file.cpp +++ b/src/coreclr/pal/src/cruntime/file.cpp @@ -522,7 +522,7 @@ PAL_fread(void * buffer, size_t size, size_t count, PAL_FILE * f) } else { - temp[nCount++]=nChar; + temp[nCount++]= (char)nChar; } } } diff --git a/src/coreclr/pal/src/cruntime/printf.cpp b/src/coreclr/pal/src/cruntime/printf.cpp index 00c7d70c8af58..c312a935656f9 100644 --- a/src/coreclr/pal/src/cruntime/printf.cpp +++ b/src/coreclr/pal/src/cruntime/printf.cpp @@ -265,7 +265,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, if (*Fmt && **Fmt == '%') { - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; } else { @@ -285,7 +285,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, if (**Fmt == '*') { *Store = FALSE; - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; } /* grab width specifier */ @@ -294,8 +294,8 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, TempStrPtr = TempStr; while (isdigit(**Fmt)) { - *TempStrPtr++ = **Fmt; - *Out++ = *(*Fmt)++; + *TempStrPtr++ = (CHAR)**Fmt; + *Out++ = (CHAR)*(*Fmt)++; } *TempStrPtr = 0; /* end string */ *Width = atoi(TempStr); @@ -406,7 +406,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, Out += strlen(scanf_longlongfmt); } - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; Result = TRUE; } else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || @@ -416,7 +416,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, *Type = SCANF_TYPE_FLOAT; /* this gets rid of %E/%G since they're they're the same when scanning */ - *Out++ = tolower( *(*Fmt)++ ); + *Out++ = (CHAR)tolower( *(*Fmt)++ ); Result = TRUE; } else if (**Fmt == 'n') @@ -425,7 +425,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, { *Out++ = 'h'; } - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; *Type = SCANF_TYPE_N; Result = TRUE; } @@ -489,8 +489,8 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, unsigned char prev, next; /* get the interval boundaries */ - prev = (*Fmt)[-1]; - next = (*Fmt)[1]; + prev = (unsigned char)(*Fmt)[-1]; + next = (unsigned char)(*Fmt)[1]; /* if boundaries were inverted, replace the already-copied low boundary by the 'real' low boundary */ @@ -514,7 +514,7 @@ static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, else { /* plain character; just copy it */ - *Out++ = **Fmt; + *Out++ = (CHAR)**Fmt; (*Fmt)++; } } @@ -625,7 +625,7 @@ int PAL_wvsscanf(LPCWSTR Buffer, LPCWSTR Format, va_list ap) { if (Prefix == SCANF_PREFIX_SHORT) { - *(va_arg(ap, short *)) = Buff - Buffer; + *(va_arg(ap, short *)) = (short)(Buff - Buffer); } else { diff --git a/src/coreclr/pal/src/cruntime/printfcpp.cpp b/src/coreclr/pal/src/cruntime/printfcpp.cpp index e014fe015e21f..ae37ffbf1a27a 100644 --- a/src/coreclr/pal/src/cruntime/printfcpp.cpp +++ b/src/coreclr/pal/src/cruntime/printfcpp.cpp @@ -706,7 +706,7 @@ BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, L *Out++ = 'l'; *Out++ = 'l'; } - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; Result = TRUE; } else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || @@ -719,7 +719,7 @@ BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, L } *Type = PFF_TYPE_FLOAT; - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; Result = TRUE; } else if (**Fmt == 'n') @@ -733,7 +733,7 @@ BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, L { *Out++ = 'h'; } - *Out++ = *(*Fmt)++; + *Out++ = (CHAR)*(*Fmt)++; *Type = PFF_TYPE_N; Result = TRUE; } @@ -1220,8 +1220,8 @@ int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *for TempInt = va_arg(ap, INT); /* value not used */ } - TempWChar[0] = va_arg(ap, int); - TempWChar[1] = 0; + TempWChar[0] = (WCHAR)va_arg(ap, int); + TempWChar[1] = W('\0'); /* do the padding (if needed)*/ paddingReturnValue = @@ -1254,7 +1254,7 @@ int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *for if (Prefix == PFF_PREFIX_SHORT) { - *(va_arg(ap, short *)) = written; + *(va_arg(ap, short *)) = (short)written; } else { @@ -1605,7 +1605,7 @@ int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, TempInt = va_arg(ap, INT); /* value not used */ } - TempWChar = va_arg(ap, int); + TempWChar = (WCHAR)va_arg(ap, int); Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1, TempBuffer, sizeof(TempBuffer), 0, 0); @@ -1617,7 +1617,7 @@ int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_end(ap); return -1; } - TempBuffer[Length] = 0; + TempBuffer[Length] = W('\0'); /* do the padding (if needed)*/ paddingReturnValue = @@ -1648,7 +1648,7 @@ int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, if (Prefix == PFF_PREFIX_SHORT) { - *(va_arg(ap, short *)) = written; + *(va_arg(ap, short *)) = (short)written; } else { diff --git a/src/coreclr/pal/src/cruntime/silent_printf.cpp b/src/coreclr/pal/src/cruntime/silent_printf.cpp index 17e3007c762fc..05a0e85906c81 100644 --- a/src/coreclr/pal/src/cruntime/silent_printf.cpp +++ b/src/coreclr/pal/src/cruntime/silent_printf.cpp @@ -168,7 +168,7 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg) TempInt = va_arg(ap, INT); /* value not used */ } - TempWChar = va_arg(ap, int); + TempWChar = (WCHAR)va_arg(ap, int); Length = Silent_WideCharToMultiByte(&TempWChar, 1, TempBuffer, 4); if (!Length) { @@ -204,7 +204,7 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg) if (Prefix == PFF_PREFIX_SHORT) { - *(va_arg(ap, short *)) = written; + *(va_arg(ap, short *)) = (short)written; } else { diff --git a/src/coreclr/pal/src/exception/remote-unwind.cpp b/src/coreclr/pal/src/exception/remote-unwind.cpp index 514851fa2244e..ebeb466d66feb 100644 --- a/src/coreclr/pal/src/exception/remote-unwind.cpp +++ b/src/coreclr/pal/src/exception/remote-unwind.cpp @@ -124,7 +124,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size #define PRId PRId32 #define PRIA "08" #define PRIxA PRIA PRIx -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X) || defined(TARGET_LOONGARCH64) +#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_S390X) || defined(TARGET_LOONGARCH64) || defined(TARGET_POWERPC64) #define PRIx PRIx64 #define PRIu PRIu64 #define PRId PRId64 @@ -1872,6 +1872,25 @@ static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, GetContextPointer(cursor, unwContext, UNW_S390X_R13, &contextPointers->R13); GetContextPointer(cursor, unwContext, UNW_S390X_R14, &contextPointers->R14); GetContextPointer(cursor, unwContext, UNW_S390X_R15, &contextPointers->R15); +#elif defined(TARGET_POWERPC64) + GetContextPointer(cursor, unwContext, UNW_PPC64_R14, &contextPointers->R14); + GetContextPointer(cursor, unwContext, UNW_PPC64_R15, &contextPointers->R15); + GetContextPointer(cursor, unwContext, UNW_PPC64_R16, &contextPointers->R16); + GetContextPointer(cursor, unwContext, UNW_PPC64_R17, &contextPointers->R17); + GetContextPointer(cursor, unwContext, UNW_PPC64_R18, &contextPointers->R18); + GetContextPointer(cursor, unwContext, UNW_PPC64_R19, &contextPointers->R19); + GetContextPointer(cursor, unwContext, UNW_PPC64_R20, &contextPointers->R20); + GetContextPointer(cursor, unwContext, UNW_PPC64_R21, &contextPointers->R21); + GetContextPointer(cursor, unwContext, UNW_PPC64_R22, &contextPointers->R22); + GetContextPointer(cursor, unwContext, UNW_PPC64_R23, &contextPointers->R23); + GetContextPointer(cursor, unwContext, UNW_PPC64_R24, &contextPointers->R24); + GetContextPointer(cursor, unwContext, UNW_PPC64_R25, &contextPointers->R25); + GetContextPointer(cursor, unwContext, UNW_PPC64_R26, &contextPointers->R26); + GetContextPointer(cursor, unwContext, UNW_PPC64_R27, &contextPointers->R27); + GetContextPointer(cursor, unwContext, UNW_PPC64_R28, &contextPointers->R28); + GetContextPointer(cursor, unwContext, UNW_PPC64_R29, &contextPointers->R29); + GetContextPointer(cursor, unwContext, UNW_PPC64_R30, &contextPointers->R30); + GetContextPointer(cursor, unwContext, UNW_PPC64_R31, &contextPointers->R31); #else #error unsupported architecture #endif @@ -1959,6 +1978,27 @@ static void UnwindContextToContext(unw_cursor_t *cursor, CONTEXT *winContext) unw_get_reg(cursor, UNW_S390X_R13, (unw_word_t *) &winContext->R13); unw_get_reg(cursor, UNW_S390X_R14, (unw_word_t *) &winContext->R14); TRACE("sp %p pc %p lr %p\n", winContext->R15, winContext->PSWAddr, winContext->R14); +#elif defined(TARGET_POWERPC64) + //TODO + unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Nip); + unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->R31); + unw_get_reg(cursor, UNW_PPC64_R14, (unw_word_t *) &winContext->R14); + unw_get_reg(cursor, UNW_PPC64_R15, (unw_word_t *) &winContext->R15); + unw_get_reg(cursor, UNW_PPC64_R16, (unw_word_t *) &winContext->R16); + unw_get_reg(cursor, UNW_PPC64_R17, (unw_word_t *) &winContext->R17); + unw_get_reg(cursor, UNW_PPC64_R18, (unw_word_t *) &winContext->R18); + unw_get_reg(cursor, UNW_PPC64_R19, (unw_word_t *) &winContext->R19); + unw_get_reg(cursor, UNW_PPC64_R20, (unw_word_t *) &winContext->R20); + unw_get_reg(cursor, UNW_PPC64_R21, (unw_word_t *) &winContext->R21); + unw_get_reg(cursor, UNW_PPC64_R22, (unw_word_t *) &winContext->R22); + unw_get_reg(cursor, UNW_PPC64_R23, (unw_word_t *) &winContext->R23); + unw_get_reg(cursor, UNW_PPC64_R24, (unw_word_t *) &winContext->R24); + unw_get_reg(cursor, UNW_PPC64_R25, (unw_word_t *) &winContext->R25); + unw_get_reg(cursor, UNW_PPC64_R26, (unw_word_t *) &winContext->R26); + unw_get_reg(cursor, UNW_PPC64_R27, (unw_word_t *) &winContext->R27); + unw_get_reg(cursor, UNW_PPC64_R28, (unw_word_t *) &winContext->R28); + unw_get_reg(cursor, UNW_PPC64_R29, (unw_word_t *) &winContext->R29); + unw_get_reg(cursor, UNW_PPC64_R30, (unw_word_t *) &winContext->R30); #else #error unsupported architecture #endif @@ -2073,6 +2113,27 @@ access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write case UNW_S390X_R14: *valp = (unw_word_t)winContext->R14; break; case UNW_S390X_R15: *valp = (unw_word_t)winContext->R15; break; case UNW_S390X_IP: *valp = (unw_word_t)winContext->PSWAddr; break; +#elif defined(TARGET_POWERPC64) + //TODO + case UNW_PPC64_R14: *valp = (unw_word_t)winContext->R14; break; + case UNW_PPC64_R15: *valp = (unw_word_t)winContext->R15; break; + case UNW_PPC64_R16: *valp = (unw_word_t)winContext->R16; break; + case UNW_PPC64_R17: *valp = (unw_word_t)winContext->R17; break; + case UNW_PPC64_R18: *valp = (unw_word_t)winContext->R18; break; + case UNW_PPC64_R19: *valp = (unw_word_t)winContext->R19; break; + case UNW_PPC64_R20: *valp = (unw_word_t)winContext->R20; break; + case UNW_PPC64_R21: *valp = (unw_word_t)winContext->R21; break; + case UNW_PPC64_R22: *valp = (unw_word_t)winContext->R22; break; + case UNW_PPC64_R23: *valp = (unw_word_t)winContext->R23; break; + case UNW_PPC64_R24: *valp = (unw_word_t)winContext->R24; break; + case UNW_PPC64_R25: *valp = (unw_word_t)winContext->R25; break; + case UNW_PPC64_R26: *valp = (unw_word_t)winContext->R26; break; + case UNW_PPC64_R27: *valp = (unw_word_t)winContext->R27; break; + case UNW_PPC64_R28: *valp = (unw_word_t)winContext->R28; break; + case UNW_PPC64_R29: *valp = (unw_word_t)winContext->R29; break; + case UNW_PPC64_R30: *valp = (unw_word_t)winContext->R30; break; + case UNW_PPC64_R31: *valp = (unw_word_t)winContext->R31; break; + case UNW_PPC64_NIP: *valp = (unw_word_t)winContext->Nip; break; #else #error unsupported architecture #endif diff --git a/src/coreclr/pal/src/exception/seh-unwind.cpp b/src/coreclr/pal/src/exception/seh-unwind.cpp index fd9756dffa31b..9fe6c61d0f828 100644 --- a/src/coreclr/pal/src/exception/seh-unwind.cpp +++ b/src/coreclr/pal/src/exception/seh-unwind.cpp @@ -152,6 +152,27 @@ enum ASSIGN_REG(S6) \ ASSIGN_REG(S7) \ ASSIGN_REG(S8) +#elif (defined(HOST_UNIX) && defined(HOST_POWERPC64)) +#define ASSIGN_UNWIND_REGS \ + ASSIGN_REG(Nip) \ + ASSIGN_REG(R14) \ + ASSIGN_REG(R15) \ + ASSIGN_REG(R16) \ + ASSIGN_REG(R17) \ + ASSIGN_REG(R18) \ + ASSIGN_REG(R19) \ + ASSIGN_REG(R20) \ + ASSIGN_REG(R21) \ + ASSIGN_REG(R22) \ + ASSIGN_REG(R23) \ + ASSIGN_REG(R24) \ + ASSIGN_REG(R25) \ + ASSIGN_REG(R26) \ + ASSIGN_REG(R27) \ + ASSIGN_REG(R28) \ + ASSIGN_REG(R29) \ + ASSIGN_REG(R30) \ + ASSIGN_REG(R31) #else #error unsupported architecture #endif @@ -390,6 +411,26 @@ void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext) unw_get_reg(cursor, UNW_LOONGARCH64_R29, (unw_word_t *) &winContext->S6); unw_get_reg(cursor, UNW_LOONGARCH64_R30, (unw_word_t *) &winContext->S7); unw_get_reg(cursor, UNW_LOONGARCH64_R31, (unw_word_t *) &winContext->S8); +#elif (defined(HOST_UNIX) && defined(HOST_POWERPC64)) + unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->R31); + unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Nip); + unw_get_reg(cursor, UNW_PPC64_R14, (unw_word_t *) &winContext->R14); + unw_get_reg(cursor, UNW_PPC64_R15, (unw_word_t *) &winContext->R15); + unw_get_reg(cursor, UNW_PPC64_R16, (unw_word_t *) &winContext->R16); + unw_get_reg(cursor, UNW_PPC64_R17, (unw_word_t *) &winContext->R17); + unw_get_reg(cursor, UNW_PPC64_R18, (unw_word_t *) &winContext->R18); + unw_get_reg(cursor, UNW_PPC64_R19, (unw_word_t *) &winContext->R19); + unw_get_reg(cursor, UNW_PPC64_R20, (unw_word_t *) &winContext->R20); + unw_get_reg(cursor, UNW_PPC64_R21, (unw_word_t *) &winContext->R21); + unw_get_reg(cursor, UNW_PPC64_R22, (unw_word_t *) &winContext->R22); + unw_get_reg(cursor, UNW_PPC64_R23, (unw_word_t *) &winContext->R23); + unw_get_reg(cursor, UNW_PPC64_R24, (unw_word_t *) &winContext->R24); + unw_get_reg(cursor, UNW_PPC64_R25, (unw_word_t *) &winContext->R25); + unw_get_reg(cursor, UNW_PPC64_R26, (unw_word_t *) &winContext->R26); + unw_get_reg(cursor, UNW_PPC64_R27, (unw_word_t *) &winContext->R27); + unw_get_reg(cursor, UNW_PPC64_R28, (unw_word_t *) &winContext->R28); + unw_get_reg(cursor, UNW_PPC64_R29, (unw_word_t *) &winContext->R29); + unw_get_reg(cursor, UNW_PPC64_R30, (unw_word_t *) &winContext->R30); #else #error unsupported architecture #endif @@ -488,6 +529,25 @@ void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOL GetContextPointer(cursor, unwContext, UNW_LOONGARCH64_R29, &contextPointers->S6); GetContextPointer(cursor, unwContext, UNW_LOONGARCH64_R30, &contextPointers->S7); GetContextPointer(cursor, unwContext, UNW_LOONGARCH64_R31, &contextPointers->S8); +#elif (defined(HOST_UNIX) && defined(HOST_POWERPC64)) + GetContextPointer(cursor, unwContext, UNW_PPC64_R14, &contextPointers->R14); + GetContextPointer(cursor, unwContext, UNW_PPC64_R15, &contextPointers->R15); + GetContextPointer(cursor, unwContext, UNW_PPC64_R16, &contextPointers->R16); + GetContextPointer(cursor, unwContext, UNW_PPC64_R17, &contextPointers->R17); + GetContextPointer(cursor, unwContext, UNW_PPC64_R18, &contextPointers->R18); + GetContextPointer(cursor, unwContext, UNW_PPC64_R19, &contextPointers->R19); + GetContextPointer(cursor, unwContext, UNW_PPC64_R20, &contextPointers->R20); + GetContextPointer(cursor, unwContext, UNW_PPC64_R21, &contextPointers->R21); + GetContextPointer(cursor, unwContext, UNW_PPC64_R22, &contextPointers->R22); + GetContextPointer(cursor, unwContext, UNW_PPC64_R23, &contextPointers->R23); + GetContextPointer(cursor, unwContext, UNW_PPC64_R24, &contextPointers->R24); + GetContextPointer(cursor, unwContext, UNW_PPC64_R25, &contextPointers->R25); + GetContextPointer(cursor, unwContext, UNW_PPC64_R26, &contextPointers->R26); + GetContextPointer(cursor, unwContext, UNW_PPC64_R27, &contextPointers->R27); + GetContextPointer(cursor, unwContext, UNW_PPC64_R28, &contextPointers->R28); + GetContextPointer(cursor, unwContext, UNW_PPC64_R29, &contextPointers->R29); + GetContextPointer(cursor, unwContext, UNW_PPC64_R30, &contextPointers->R30); + GetContextPointer(cursor, unwContext, UNW_PPC64_R31, &contextPointers->R31); #else #error unsupported architecture #endif diff --git a/src/coreclr/pal/src/file/filetime.cpp b/src/coreclr/pal/src/file/filetime.cpp index 768ee426c4dbf..ea8ca6bd0535a 100644 --- a/src/coreclr/pal/src/file/filetime.cpp +++ b/src/coreclr/pal/src/file/filetime.cpp @@ -294,16 +294,16 @@ BOOL PALAPI FileTimeToSystemTime( CONST FILETIME * lpFileTime, #endif /* HAVE_GMTIME_R */ /* Convert unix system time to Windows system time. */ - lpSystemTime->wDay = UnixSystemTime->tm_mday; + lpSystemTime->wDay = (WORD)UnixSystemTime->tm_mday; /* Unix time counts January as a 0, under Windows it is 1*/ - lpSystemTime->wMonth = UnixSystemTime->tm_mon + 1; + lpSystemTime->wMonth = (WORD)UnixSystemTime->tm_mon + 1; /* Unix time returns the year - 1900, Windows returns the current year*/ - lpSystemTime->wYear = UnixSystemTime->tm_year + 1900; + lpSystemTime->wYear = (WORD)UnixSystemTime->tm_year + 1900; - lpSystemTime->wSecond = UnixSystemTime->tm_sec; - lpSystemTime->wMinute = UnixSystemTime->tm_min; - lpSystemTime->wHour = UnixSystemTime->tm_hour; + lpSystemTime->wSecond = (WORD)UnixSystemTime->tm_sec; + lpSystemTime->wMinute = (WORD)UnixSystemTime->tm_min; + lpSystemTime->wHour = (WORD)UnixSystemTime->tm_hour; return TRUE; } else diff --git a/src/coreclr/pal/src/include/pal/context.h b/src/coreclr/pal/src/include/pal/context.h index fd37f92693c41..fec5139fd5e40 100644 --- a/src/coreclr/pal/src/include/pal/context.h +++ b/src/coreclr/pal/src/include/pal/context.h @@ -75,6 +75,47 @@ using asm_sigcontext::_xstate; #define MCREG_R14(mc) ((mc).gregs[14]) #define MCREG_R15(mc) ((mc).gregs[15]) +#elif HOST_POWERPC64 + +#define MCREG_R0(mc) ((mc).gp_regs[0]) +#define MCREG_R1(mc) ((mc).gp_regs[1]) +#define MCREG_R2(mc) ((mc).gp_regs[2]) +#define MCREG_R3(mc) ((mc).gp_regs[3]) +#define MCREG_R4(mc) ((mc).gp_regs[4]) +#define MCREG_R5(mc) ((mc).gp_regs[5]) +#define MCREG_R6(mc) ((mc).gp_regs[6]) +#define MCREG_R7(mc) ((mc).gp_regs[7]) +#define MCREG_R8(mc) ((mc).gp_regs[8]) +#define MCREG_R9(mc) ((mc).gp_regs[9]) +#define MCREG_R10(mc) ((mc).gp_regs[10]) +#define MCREG_R11(mc) ((mc).gp_regs[11]) +#define MCREG_R12(mc) ((mc).gp_regs[12]) +#define MCREG_R13(mc) ((mc).gp_regs[13]) +#define MCREG_R14(mc) ((mc).gp_regs[14]) +#define MCREG_R15(mc) ((mc).gp_regs[15]) +#define MCREG_R16(mc) ((mc).gp_regs[16]) +#define MCREG_R17(mc) ((mc).gp_regs[17]) +#define MCREG_R18(mc) ((mc).gp_regs[18]) +#define MCREG_R19(mc) ((mc).gp_regs[19]) +#define MCREG_R20(mc) ((mc).gp_regs[20]) +#define MCREG_R21(mc) ((mc).gp_regs[21]) +#define MCREG_R22(mc) ((mc).gp_regs[22]) +#define MCREG_R23(mc) ((mc).gp_regs[23]) +#define MCREG_R24(mc) ((mc).gp_regs[24]) +#define MCREG_R25(mc) ((mc).gp_regs[25]) +#define MCREG_R26(mc) ((mc).gp_regs[26]) +#define MCREG_R27(mc) ((mc).gp_regs[27]) +#define MCREG_R28(mc) ((mc).gp_regs[28]) +#define MCREG_R29(mc) ((mc).gp_regs[29]) +#define MCREG_R30(mc) ((mc).gp_regs[30]) +#define MCREG_R31(mc) ((mc).gp_regs[31]) +#define MCREG_Nip(mc) ((mc).gp_regs[32]) +#define MCREG_Msr(mc) ((mc).gp_regs[33]) +#define MCREG_Ctr(mc) ((mc).gp_regs[35]) +#define MCREG_Link(mc) ((mc).gp_regs[36]) +#define MCREG_Xer(mc) ((mc).gp_regs[37]) +#define MCREG_Ccr(mc) ((mc).gp_regs[38]) + #elif HAVE___GREGSET_T #ifdef HOST_64BIT @@ -756,6 +797,47 @@ const VfpSigFrame* GetConstNativeSigSimdContext(const native_context_t *mc) #define PTREG_Pc(ptreg) ((ptreg).csr_epc) #endif // HOST_LOONGARCH64 +#if defined(HOST_POWERPC64) +#define PTREG_R0(ptreg) ((ptreg).gpr[0]) +#define PTREG_R1(ptreg) ((ptreg).gpr[1]) +#define PTREG_R2(ptreg) ((ptreg).gpr[2]) +#define PTREG_R3(ptreg) ((ptreg).gpr[3]) +#define PTREG_R4(ptreg) ((ptreg).gpr[4]) +#define PTREG_R5(ptreg) ((ptreg).gpr[5]) +#define PTREG_R6(ptreg) ((ptreg).gpr[6]) +#define PTREG_R7(ptreg) ((ptreg).gpr[7]) +#define PTREG_R8(ptreg) ((ptreg).gpr[8]) +#define PTREG_R9(ptreg) ((ptreg).gpr[9]) +#define PTREG_R10(ptreg) ((ptreg).gpr[10]) +#define PTREG_R11(ptreg) ((ptreg).gpr[11]) +#define PTREG_R12(ptreg) ((ptreg).gpr[12]) +#define PTREG_R13(ptreg) ((ptreg).gpr[13]) +#define PTREG_R14(ptreg) ((ptreg).gpr[14]) +#define PTREG_R15(ptreg) ((ptreg).gpr[15]) +#define PTREG_R16(ptreg) ((ptreg).gpr[16]) +#define PTREG_R17(ptreg) ((ptreg).gpr[17]) +#define PTREG_R18(ptreg) ((ptreg).gpr[18]) +#define PTREG_R19(ptreg) ((ptreg).gpr[19]) +#define PTREG_R20(ptreg) ((ptreg).gpr[20]) +#define PTREG_R21(ptreg) ((ptreg).gpr[21]) +#define PTREG_R22(ptreg) ((ptreg).gpr[22]) +#define PTREG_R23(ptreg) ((ptreg).gpr[23]) +#define PTREG_R24(ptreg) ((ptreg).gpr[24]) +#define PTREG_R25(ptreg) ((ptreg).gpr[25]) +#define PTREG_R26(ptreg) ((ptreg).gpr[26]) +#define PTREG_R27(ptreg) ((ptreg).gpr[27]) +#define PTREG_R28(ptreg) ((ptreg).gpr[28]) +#define PTREG_R29(ptreg) ((ptreg).gpr[29]) +#define PTREG_R30(ptreg) ((ptreg).gpr[30]) +#define PTREG_R31(ptreg) ((ptreg).gpr[31]) +#define PTREG_Nip(ptreg) ((ptreg).nip) +#define PTREG_Msr(ptreg) ((ptreg).msr) +#define PTREG_Ctr(ptreg) ((ptreg).ctr) +#define PTREG_Link(ptreg) ((ptreg).link) +#define PTREG_Xer(ptreg) ((ptreg).xer) +#define PTREG_Ccr(ptreg) ((ptreg).ccr) +#else //HOST_POWERPC64 + #define PTREG_Rbx(ptreg) ((ptreg).rbx) #define PTREG_Rcx(ptreg) ((ptreg).rcx) #define PTREG_Rdx(ptreg) ((ptreg).rdx) @@ -776,6 +858,7 @@ const VfpSigFrame* GetConstNativeSigSimdContext(const native_context_t *mc) #define PTREG_R14(ptreg) ((ptreg).r14) #define PTREG_R15(ptreg) ((ptreg).r15) +#endif //HOST_POWERPC64 #else // HOST_64BIT #if defined(HOST_ARM) @@ -881,6 +964,8 @@ inline static DWORD64 CONTEXTGetPC(LPCONTEXT pContext) return pContext->Pc; #elif defined(HOST_S390X) return pContext->PSWAddr; +#elif defined(HOST_POWERPC64) + return pContext->Nip; #else #error "don't know how to get the program counter for this architecture" #endif @@ -898,6 +983,8 @@ inline static void CONTEXTSetPC(LPCONTEXT pContext, DWORD64 pc) pContext->Pc = pc; #elif defined(HOST_S390X) pContext->PSWAddr = pc; +#elif defined(HOST_POWERPC64) + pContext->Nip = pc; #else #error "don't know how to set the program counter for this architecture" #endif @@ -917,6 +1004,8 @@ inline static DWORD64 CONTEXTGetFP(LPCONTEXT pContext) return pContext->Fp; #elif defined(HOST_S390X) return pContext->R11; +#elif defined(HOST_POWERPC64) + return pContext->R31; #else #error "don't know how to get the frame pointer for this architecture" #endif diff --git a/src/coreclr/pal/src/include/pal/virtual.h b/src/coreclr/pal/src/include/pal/virtual.h index bac28112ba378..902e3f4fdd6f6 100644 --- a/src/coreclr/pal/src/include/pal/virtual.h +++ b/src/coreclr/pal/src/include/pal/virtual.h @@ -180,17 +180,24 @@ class ExecutableMemoryAllocator int32_t GenerateRandomStartOffset(); private: + // There does not seem to be an easy way find the size of a library on Unix. - // So this constant represents an approximation of the libcoreclr size (on debug build) + // So this constant represents an approximation of the libcoreclr size // that can be used to calculate an approximate location of the memory that // is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr // is not necessary for the calculations. - static const int32_t CoreClrLibrarySize = 100 * 1024 * 1024; + static const int32_t CoreClrLibrarySize = 16 * 1024 * 1024; // This constant represent the max size of the virtual memory that this allocator // will try to reserve during initialization. We want all JIT-ed code and the - // entire libcoreclr to be located in a 2GB range. + // entire libcoreclr to be located in a 2GB range on x86 +#if defined(TARGET_ARM) || defined(TARGET_ARM64) + // It seems to be more difficult to reserve a 2Gb chunk on arm so we'll try smaller one + static const int32_t MaxExecutableMemorySize = 1024 * 1024 * 1024; +#else static const int32_t MaxExecutableMemorySize = 0x7FFF0000; +#endif + static const int32_t MaxExecutableMemorySizeNearCoreClr = MaxExecutableMemorySize - CoreClrLibrarySize; // Start address of the reserved virtual address space diff --git a/src/coreclr/pal/src/locale/utf8.cpp b/src/coreclr/pal/src/locale/utf8.cpp index 8ff3229fcbaba..c0cf19dba5d7f 100644 --- a/src/coreclr/pal/src/locale/utf8.cpp +++ b/src/coreclr/pal/src/locale/utf8.cpp @@ -1075,7 +1075,7 @@ class UTF8Encoding DecoderReplacementFallback decoderReplacementFallback; DecoderExceptionFallback decoderExceptionFallback; - bool InRange(WCHAR c, WCHAR begin, WCHAR end) + bool InRange(int c, int begin, int end) { return begin <= c && c <= end; } diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp index 55b6aa3fecf0e..ad3a453aa539f 100644 --- a/src/coreclr/pal/src/map/map.cpp +++ b/src/coreclr/pal/src/map/map.cpp @@ -2284,7 +2284,13 @@ void * MAPMapPEFile(HANDLE hFile, off_t offset) // more efficient code (by avoiding usage of jump stubs). Alignment to a 64 KB granularity should // not be necessary (alignment to page size should be sufficient), but see // ExecutableMemoryAllocator::AllocateMemory() for the reason why it is done. - loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(reserveSize, VIRTUAL_64KB)); + +#ifdef FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION + if (!g_useDefaultBaseAddr) +#endif // FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION + { + loadedBase = ReserveMemoryFromExecutableAllocator(pThread, ALIGN_UP(reserveSize, VIRTUAL_64KB)); + } #endif // HOST_64BIT if (loadedBase == NULL) diff --git a/src/coreclr/pal/src/map/virtual.cpp b/src/coreclr/pal/src/map/virtual.cpp index 64ecf1ff48a84..8f4c87e67e4bf 100644 --- a/src/coreclr/pal/src/map/virtual.cpp +++ b/src/coreclr/pal/src/map/virtual.cpp @@ -2140,7 +2140,15 @@ void ExecutableMemoryAllocator::TryReserveInitialMemory() int32_t preferredStartAddressIncrement; UINT_PTR preferredStartAddress; UINT_PTR coreclrLoadAddress; - const int32_t MemoryProbingIncrement = 128 * 1024 * 1024; + +#if defined(TARGET_ARM) || defined(TARGET_ARM64) + // Smaller steps on ARM because we try hard finding a spare memory in a 128Mb + // distance from coreclr so e.g. all calls from corelib to coreclr could use relocs + const int32_t AddressProbingIncrement = 8 * 1024 * 1024; +#else + const int32_t AddressProbingIncrement = 128 * 1024 * 1024; +#endif + const int32_t SizeProbingDecrement = 128 * 1024 * 1024; // Try to find and reserve an available region of virtual memory that is located // within 2GB range (defined by the MaxExecutableMemorySizeNearCoreClr constant) from the @@ -2161,12 +2169,18 @@ void ExecutableMemoryAllocator::TryReserveInitialMemory() { // Try to allocate above the location of libcoreclr preferredStartAddress = coreclrLoadAddress + CoreClrLibrarySize; - preferredStartAddressIncrement = MemoryProbingIncrement; + preferredStartAddressIncrement = AddressProbingIncrement; } else { // Try to allocate below the location of libcoreclr - preferredStartAddress = coreclrLoadAddress - MaxExecutableMemorySizeNearCoreClr; +#if defined(TARGET_ARM) || defined(TARGET_ARM64) + // For arm for the "high address" case it only makes sense to try to reserve 128Mb + // and if it doesn't work - we'll reserve a full-sized region in a random location + sizeOfAllocation = SizeProbingDecrement; +#endif + + preferredStartAddress = coreclrLoadAddress - sizeOfAllocation; preferredStartAddressIncrement = 0; } @@ -2180,10 +2194,10 @@ void ExecutableMemoryAllocator::TryReserveInitialMemory() } // Try to allocate a smaller region - sizeOfAllocation -= MemoryProbingIncrement; + sizeOfAllocation -= SizeProbingDecrement; preferredStartAddress += preferredStartAddressIncrement; - } while (sizeOfAllocation >= MemoryProbingIncrement); + } while (sizeOfAllocation >= SizeProbingDecrement); if (m_startAddress == nullptr) { diff --git a/src/coreclr/pal/src/misc/cgroup.cpp b/src/coreclr/pal/src/misc/cgroup.cpp index 955347ceda65d..890ddf38363d6 100644 --- a/src/coreclr/pal/src/misc/cgroup.cpp +++ b/src/coreclr/pal/src/misc/cgroup.cpp @@ -38,6 +38,10 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC); #define CGROUP1_MEMORY_LIMIT_FILENAME "/memory.limit_in_bytes" #define CGROUP2_MEMORY_LIMIT_FILENAME "/memory.max" #define CGROUP_MEMORY_STAT_FILENAME "/memory.stat" +#define CGROUP1_MEMORY_USAGE_FILENAME "/memory.usage_in_bytes" +#define CGROUP2_MEMORY_USAGE_FILENAME "/memory.current" +#define CGROUP1_MEMORY_STAT_INACTIVE_FIELD "total_inactive_file " +#define CGROUP2_MEMORY_STAT_INACTIVE_FIELD "inactive_file " #define CGROUP1_CFS_QUOTA_FILENAME "/cpu.cfs_quota_us" #define CGROUP1_CFS_PERIOD_FILENAME "/cpu.cfs_period_us" #define CGROUP2_CPU_MAX_FILENAME "/cpu.max" @@ -49,37 +53,12 @@ class CGroup static char *s_memory_cgroup_path; static char *s_cpu_cgroup_path; - - static const char *s_mem_stat_key_names[]; - static size_t s_mem_stat_key_lengths[]; - static size_t s_mem_stat_n_keys; public: static void Initialize() { s_cgroup_version = FindCGroupVersion(); s_memory_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1MemorySubsystem : nullptr); s_cpu_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1CpuSubsystem : nullptr); - - if (s_cgroup_version == 1) - { - s_mem_stat_n_keys = 4; - s_mem_stat_key_names[0] = "total_inactive_anon "; - s_mem_stat_key_names[1] = "total_active_anon "; - s_mem_stat_key_names[2] = "total_dirty "; - s_mem_stat_key_names[3] = "total_unevictable "; - } - else - { - s_mem_stat_n_keys = 3; - s_mem_stat_key_names[0] = "anon "; - s_mem_stat_key_names[1] = "file_dirty "; - s_mem_stat_key_names[2] = "unevictable "; - } - - for (size_t i = 0; i < s_mem_stat_n_keys; i++) - { - s_mem_stat_key_lengths[i] = strlen(s_mem_stat_key_names[i]); - } } static void Cleanup() @@ -108,9 +87,9 @@ class CGroup if (s_cgroup_version == 0) return false; else if (s_cgroup_version == 1) - return GetCGroupMemoryUsage(val); + return GetCGroupMemoryUsage(val, CGROUP1_MEMORY_USAGE_FILENAME, CGROUP1_MEMORY_STAT_INACTIVE_FIELD); else if (s_cgroup_version == 2) - return GetCGroupMemoryUsage(val); + return GetCGroupMemoryUsage(val, CGROUP2_MEMORY_USAGE_FILENAME, CGROUP2_MEMORY_STAT_INACTIVE_FIELD); else { _ASSERTE(!"Unknown cgroup version."); @@ -416,8 +395,38 @@ class CGroup return result; } - static bool GetCGroupMemoryUsage(size_t *val) + static bool GetCGroupMemoryUsage(size_t *val, const char *filename, const char *inactiveFileFieldName) { + // Use the same way to calculate memory load as popular container tools (Docker, Kubernetes, Containerd etc.) + // For cgroup v1: value of 'memory.usage_in_bytes' minus 'total_inactive_file' value of 'memory.stat' + // For cgroup v2: value of 'memory.current' minus 'inactive_file' value of 'memory.stat' + + char* mem_usage_filename = nullptr; + if (asprintf(&mem_usage_filename, "%s%s", s_memory_cgroup_path, filename) < 0) + return false; + + uint64_t temp = 0; + + size_t usage = 0; + + bool result = ReadMemoryValueFromFile(mem_usage_filename, &temp); + if (result) + { + if (temp > std::numeric_limits::max()) + { + usage = std::numeric_limits::max(); + } + else + { + usage = (size_t)temp; + } + } + + free(mem_usage_filename); + + if (!result) + return result; + if (s_memory_cgroup_path == nullptr) return false; @@ -432,34 +441,32 @@ class CGroup char *line = nullptr; size_t lineLen = 0; - size_t readValues = 0; + bool foundInactiveFileValue = false; char* endptr; - *val = 0; - while (getline(&line, &lineLen, stat_file) != -1 && readValues < s_mem_stat_n_keys) + size_t inactiveFileFieldNameLength = strlen(inactiveFileFieldName); + + while (getline(&line, &lineLen, stat_file) != -1) { - for (size_t i = 0; i < s_mem_stat_n_keys; i++) + if (strncmp(line, inactiveFileFieldName, inactiveFileFieldNameLength) == 0) { - if (strncmp(line, s_mem_stat_key_names[i], s_mem_stat_key_lengths[i]) == 0) + errno = 0; + const char* startptr = line + inactiveFileFieldNameLength; + size_t inactiveFileValue = strtoll(startptr, &endptr, 10); + if (endptr != startptr && errno == 0) { - errno = 0; - const char* startptr = line + s_mem_stat_key_lengths[i]; - *val += strtoll(startptr, &endptr, 10); - if (endptr != startptr && errno == 0) - readValues++; - - break; + foundInactiveFileValue = true; + *val = usage - inactiveFileValue; } + + break; } } fclose(stat_file); free(line); - if (readValues == s_mem_stat_n_keys) - return true; - - return false; + return foundInactiveFileValue; } static bool ReadMemoryValueFromFile(const char* filename, uint64_t* val) @@ -624,10 +631,6 @@ int CGroup::s_cgroup_version = 0; char *CGroup::s_memory_cgroup_path = nullptr; char *CGroup::s_cpu_cgroup_path = nullptr; -const char *CGroup::s_mem_stat_key_names[4] = {}; -size_t CGroup::s_mem_stat_key_lengths[4] = {}; -size_t CGroup::s_mem_stat_n_keys = 0; - void InitializeCGroup() { CGroup::Initialize(); diff --git a/src/coreclr/pal/src/misc/perfjitdump.cpp b/src/coreclr/pal/src/misc/perfjitdump.cpp index f0c980a61efab..df7e97af53087 100644 --- a/src/coreclr/pal/src/misc/perfjitdump.cpp +++ b/src/coreclr/pal/src/misc/perfjitdump.cpp @@ -50,6 +50,8 @@ namespace ELF_MACHINE = EM_LOONGARCH, #elif defined(HOST_S390X) ELF_MACHINE = EM_S390, +#elif defined(HOST_POWERPC) + ELF_MACHINE = EM_PPC64, #else #error ELF_MACHINE unsupported for target #endif diff --git a/src/coreclr/pal/src/misc/sysinfo.cpp b/src/coreclr/pal/src/misc/sysinfo.cpp index eb679d3d24957..b8840eff00219 100644 --- a/src/coreclr/pal/src/misc/sysinfo.cpp +++ b/src/coreclr/pal/src/misc/sysinfo.cpp @@ -539,23 +539,31 @@ ReadMemoryValueFromFile(const char* filename, uint64_t* val) return result; } +#define UPDATE_CACHE_SIZE_AND_LEVEL(CACHE_LEVEL) if (size > cacheSize) { cacheSize = size; cacheLevel = CACHE_LEVEL; } + size_t PALAPI PAL_GetLogicalProcessorCacheSizeFromOS() { + size_t cacheLevel = 0; size_t cacheSize = 0; + size_t size; #ifdef _SC_LEVEL1_DCACHE_SIZE - cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL1_DCACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL1_DCACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(1) #endif #ifdef _SC_LEVEL2_CACHE_SIZE - cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL2_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL2_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(2) #endif #ifdef _SC_LEVEL3_CACHE_SIZE - cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL3_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL3_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(3) #endif #ifdef _SC_LEVEL4_CACHE_SIZE - cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL4_CACHE_SIZE)); + size = ( size_t) sysconf(_SC_LEVEL4_CACHE_SIZE); + UPDATE_CACHE_SIZE_AND_LEVEL(4) #endif #if defined(TARGET_LINUX) && !defined(HOST_ARM) && !defined(HOST_X86) @@ -566,25 +574,39 @@ PAL_GetLogicalProcessorCacheSizeFromOS() // for the platform. Currently musl and arm64 should be only cases to use // this method to determine cache size. // - size_t size; - - if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index0/size", &size)) - cacheSize = std::max(cacheSize, size); - if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index1/size", &size)) - cacheSize = std::max(cacheSize, size); - if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index2/size", &size)) - cacheSize = std::max(cacheSize, size); - if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index3/size", &size)) - cacheSize = std::max(cacheSize, size); - if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index4/size", &size)) - cacheSize = std::max(cacheSize, size); + size_t level; + char path_to_size_file[] = "/sys/devices/system/cpu/cpu0/cache/index-/size"; + char path_to_level_file[] = "/sys/devices/system/cpu/cpu0/cache/index-/level"; + int index = 40; + _ASSERTE(path_to_size_file[index] == '-'); + _ASSERTE(path_to_level_file[index] == '-'); + + for (int i = 0; i < 5; i++) + { + path_to_size_file[index] = (char)(48 + i); + + if (ReadMemoryValueFromFile(path_to_size_file, &size)) + { + path_to_level_file[index] = (char)(48 + i); + + if (ReadMemoryValueFromFile(path_to_level_file, &level)) + { + UPDATE_CACHE_SIZE_AND_LEVEL(level) + } + else + { + cacheSize = std::max(cacheSize, size); + } + } + } } #endif #if (defined(HOST_ARM64) || defined(HOST_LOONGARCH64)) && !defined(TARGET_OSX) if (cacheSize == 0) { - // It is currently expected to be missing cache size info + // We expect to get the L3 cache size for Arm64 but currently expected to be missing that info + // from most of the machines with an exceptions on some machines. // // _SC_LEVEL*_*CACHE_SIZE is not yet present. Work is in progress to enable this for arm64 // @@ -621,12 +643,43 @@ PAL_GetLogicalProcessorCacheSizeFromOS() || sysctlbyname("hw.l3cachesize", &cacheSizeFromSysctl, &sz, nullptr, 0) == 0 || sysctlbyname("hw.l2cachesize", &cacheSizeFromSysctl, &sz, nullptr, 0) == 0 || sysctlbyname("hw.l1dcachesize", &cacheSizeFromSysctl, &sz, nullptr, 0) == 0; - if (success) { _ASSERTE(cacheSizeFromSysctl > 0); - cacheSize = (size_t) cacheSizeFromSysctl; + cacheSize = ( size_t) cacheSizeFromSysctl; + } + } +#endif + +#if (defined(HOST_ARM64) || defined(HOST_LOONGARCH64)) && !defined(TARGET_OSX) + if (cacheLevel != 3) + { + // We expect to get the L3 cache size for Arm64 but currently expected to be missing that info + // from most of the machines. + // Hence, just use the following heuristics at best depending on the CPU count + // 1 ~ 4 : 4 MB + // 5 ~ 16 : 8 MB + // 17 ~ 64 : 16 MB + // 65+ : 32 MB + DWORD logicalCPUs = PAL_GetLogicalCpuCountFromOS(); + if (logicalCPUs < 5) + { + cacheSize = 4; + } + else if (logicalCPUs < 17) + { + cacheSize = 8; } + else if (logicalCPUs < 65) + { + cacheSize = 16; + } + else + { + cacheSize = 32; + } + + cacheSize *= (1024 * 1024); } #endif diff --git a/src/coreclr/pal/src/misc/time.cpp b/src/coreclr/pal/src/misc/time.cpp index ec71e5c72b06c..7d78ae930c397 100644 --- a/src/coreclr/pal/src/misc/time.cpp +++ b/src/coreclr/pal/src/misc/time.cpp @@ -82,13 +82,13 @@ GetSystemTime( goto EXIT; } - lpSystemTime->wYear = 1900 + utPtr->tm_year; - lpSystemTime->wMonth = utPtr->tm_mon + 1; - lpSystemTime->wDayOfWeek = utPtr->tm_wday; - lpSystemTime->wDay = utPtr->tm_mday; - lpSystemTime->wHour = utPtr->tm_hour; - lpSystemTime->wMinute = utPtr->tm_min; - lpSystemTime->wSecond = utPtr->tm_sec; + lpSystemTime->wYear = (WORD)(1900 + utPtr->tm_year); + lpSystemTime->wMonth = (WORD)(utPtr->tm_mon + 1); + lpSystemTime->wDayOfWeek = (WORD)utPtr->tm_wday; + lpSystemTime->wDay = (WORD)utPtr->tm_mday; + lpSystemTime->wHour = (WORD)utPtr->tm_hour; + lpSystemTime->wMinute = (WORD)utPtr->tm_min; + lpSystemTime->wSecond = (WORD)utPtr->tm_sec; if(-1 == timeofday_retval) { @@ -101,7 +101,7 @@ GetSystemTime( int old_seconds; int new_seconds; - lpSystemTime->wMilliseconds = timeval.tv_usec/tccMillieSecondsToMicroSeconds; + lpSystemTime->wMilliseconds = (WORD)(timeval.tv_usec/tccMillieSecondsToMicroSeconds); old_seconds = utPtr->tm_sec; new_seconds = timeval.tv_sec%60; diff --git a/src/coreclr/pal/src/safecrt/input.inl b/src/coreclr/pal/src/safecrt/input.inl index 3f415d695833a..e68dc42f01614 100644 --- a/src/coreclr/pal/src/safecrt/input.inl +++ b/src/coreclr/pal/src/safecrt/input.inl @@ -665,7 +665,7 @@ scanit: } else #else /* _UNICODE */ if (fl_wchar_arg) { - *(char16_t UNALIGNED *)pointer = ch; + *(char16_t UNALIGNED *)pointer = (char16_t)ch; pointer = (char16_t *)pointer + 1; #ifdef _SECURE_SCANF --array_width; @@ -867,7 +867,7 @@ getnum: if (_ISXDIGIT(ch)) { num64 <<= 4; - ch = _hextodec(ch); + ch = _hextodec((_TCHAR)ch); } else ++done_flag; @@ -910,7 +910,7 @@ getnum: if (_ISXDIGIT(ch)) { number = (number << 4); - ch = _hextodec(ch); + ch = _hextodec((_TCHAR)ch); } else ++done_flag; @@ -1262,7 +1262,7 @@ static int __cdecl _inc(miniFILE* fileptr) static void __cdecl _un_inc(int chr, miniFILE* fileptr) { if (_TEOF != chr) { - _ungettc_nolock(chr,fileptr); + _ungettc_nolock((char)chr,fileptr); } } diff --git a/src/coreclr/pal/src/safecrt/wcslwr_s.cpp b/src/coreclr/pal/src/safecrt/wcslwr_s.cpp index f80ff7bcf344a..184776f21ee95 100644 --- a/src/coreclr/pal/src/safecrt/wcslwr_s.cpp +++ b/src/coreclr/pal/src/safecrt/wcslwr_s.cpp @@ -30,7 +30,7 @@ DLLEXPORT errno_t __cdecl _wcslwr_s(char16_t *string, size_t sz) for (int i = 0; string[i] != 0; i++) { - string[i] = towlower(string[i]); + string[i] = (char16_t)towlower(string[i]); } _FILL_STRING(string, sz, length + 1); diff --git a/src/coreclr/pal/src/thread/context.cpp b/src/coreclr/pal/src/thread/context.cpp index 5c9f89d03b201..92d2ef085f3e9 100644 --- a/src/coreclr/pal/src/thread/context.cpp +++ b/src/coreclr/pal/src/thread/context.cpp @@ -45,6 +45,8 @@ extern PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode; #define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT #elif defined(HOST_S390X) #define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT +#elif defined(HOST_POWERPC64) +#define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT #else #error Unexpected architecture. #endif @@ -232,6 +234,50 @@ typedef int __ptrace_request; ASSIGN_REG(R13) \ ASSIGN_REG(R14) +#elif defined(HOST_POWERPC64) +#define ASSIGN_CONTROL_REGS \ + ASSIGN_REG(Nip) \ + ASSIGN_REG(Msr) \ + ASSIGN_REG(Ctr) \ + ASSIGN_REG(Link) \ + ASSIGN_REG(Xer) \ + ASSIGN_REG(Ccr) \ + ASSIGN_REG(R31) \ + +#define ASSIGN_INTEGER_REGS \ + ASSIGN_REG(R0) \ + ASSIGN_REG(R1) \ + ASSIGN_REG(R2) \ + ASSIGN_REG(R3) \ + ASSIGN_REG(R4) \ + ASSIGN_REG(R5) \ + ASSIGN_REG(R5) \ + ASSIGN_REG(R6) \ + ASSIGN_REG(R7) \ + ASSIGN_REG(R8) \ + ASSIGN_REG(R9) \ + ASSIGN_REG(R10) \ + ASSIGN_REG(R11) \ + ASSIGN_REG(R12) \ + ASSIGN_REG(R13) \ + ASSIGN_REG(R14) \ + ASSIGN_REG(R15) \ + ASSIGN_REG(R16) \ + ASSIGN_REG(R17) \ + ASSIGN_REG(R18) \ + ASSIGN_REG(R19) \ + ASSIGN_REG(R20) \ + ASSIGN_REG(R21) \ + ASSIGN_REG(R22) \ + ASSIGN_REG(R23) \ + ASSIGN_REG(R24) \ + ASSIGN_REG(R25) \ + ASSIGN_REG(R26) \ + ASSIGN_REG(R27) \ + ASSIGN_REG(R28) \ + ASSIGN_REG(R29) \ + ASSIGN_REG(R30) + #else #error "Don't know how to assign registers on this architecture" #endif @@ -499,7 +545,7 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) #undef ASSIGN_REG #if !HAVE_FPREGS_WITH_CW -#if (HAVE_GREGSET_T || HAVE___GREGSET_T) && !defined(HOST_S390X) && !defined(HOST_LOONGARCH64) +#if (HAVE_GREGSET_T || HAVE___GREGSET_T) && !defined(HOST_S390X) && !defined(HOST_LOONGARCH64) && !defined(HOST_POWERPC64) #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T @@ -511,7 +557,7 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. return; } -#endif // (HAVE_GREGSET_T || HAVE___GREGSET_T) && !HOST_S390X && !HOST_LOONGARCH64 +#endif // (HAVE_GREGSET_T || HAVE___GREGSET_T) && !HOST_S390X && !HOST_LOONGARCH64 && !HOST_POWERPC64 #endif // !HAVE_FPREGS_WITH_CW if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) @@ -634,7 +680,7 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex #undef ASSIGN_REG #if !HAVE_FPREGS_WITH_CW -#if (HAVE_GREGSET_T || HAVE___GREGSET_T) && !defined(HOST_S390X) && !defined(HOST_LOONGARCH64) +#if (HAVE_GREGSET_T || HAVE___GREGSET_T) && !defined(HOST_S390X) && !defined(HOST_LOONGARCH64) && !defined(HOST_POWERPC64) #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T @@ -656,7 +702,7 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE return; } -#endif // (HAVE_GREGSET_T || HAVE___GREGSET_T) && !HOST_S390X +#endif // (HAVE_GREGSET_T || HAVE___GREGSET_T) && !HOST_S390X && !HOST_POWERPC64 #endif // !HAVE_FPREGS_WITH_CW if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) @@ -785,6 +831,8 @@ LPVOID GetNativeContextPC(const native_context_t *context) return (LPVOID) MCREG_Pc(context->uc_mcontext); #elif defined(HOST_S390X) return (LPVOID) MCREG_PSWAddr(context->uc_mcontext); +#elif defined(HOST_POWERPC64) + return (LPVOID) MCREG_Nip(context->uc_mcontext); #else # error implement me for this architecture #endif @@ -817,6 +865,8 @@ LPVOID GetNativeContextSP(const native_context_t *context) return (LPVOID) MCREG_Sp(context->uc_mcontext); #elif defined(HOST_S390X) return (LPVOID) MCREG_R15(context->uc_mcontext); +#elif defined(HOST_POWERPC64) + return (LPVOID) MCREG_R31(context->uc_mcontext); #else # error implement me for this architecture #endif diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index bf3be74203bbf..c36ac0e3c8bc6 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -323,11 +323,13 @@ def add_core_root_arguments(parser, build_type_default, build_type_help): replay_parser.add_argument("-jit_path", help="Path to clrjit. Defaults to Core_Root JIT.") replay_parser.add_argument("-jitoption", action="append", help="Pass option through to the jit. Format is key=value, where key is the option name without leading COMPlus_") +# common subparser for asmdiffs and throughput base_diff_parser = argparse.ArgumentParser(add_help=False) base_diff_parser.add_argument("-base_jit_path", help="Path to baseline clrjit. Defaults to baseline JIT from rolling build, by computing baseline git hash.") base_diff_parser.add_argument("-diff_jit_path", help="Path to diff clrjit. Defaults to Core_Root JIT.") base_diff_parser.add_argument("-git_hash", help="Use this git hash as the current hash for use to find a baseline JIT. Defaults to current git hash of source tree.") base_diff_parser.add_argument("-base_git_hash", help="Use this git hash as the baseline JIT hash. Default: search for the baseline hash.") +base_diff_parser.add_argument("-jitoption", action="append", help="Option to pass to both baseline and diff JIT. Format is key=value, where key is the option name without leading COMPlus_") base_diff_parser.add_argument("-base_jit_option", action="append", help="Option to pass to the baseline JIT. Format is key=value, where key is the option name without leading COMPlus_...") base_diff_parser.add_argument("-diff_jit_option", action="append", help="Option to pass to the diff JIT. Format is key=value, where key is the option name without leading COMPlus_...") @@ -1465,6 +1467,9 @@ def replay_with_asm_diffs(self): if self.coreclr_args.base_jit_option: for o in self.coreclr_args.base_jit_option: base_option_flags += "-jitoption", o + if self.coreclr_args.jitoption: + for o in self.coreclr_args.jitoption: + base_option_flags += "-jitoption", o base_option_flags_for_diff_artifact = base_option_flags diff_option_flags = [] @@ -1473,6 +1478,10 @@ def replay_with_asm_diffs(self): for o in self.coreclr_args.diff_jit_option: diff_option_flags += "-jit2option", o diff_option_flags_for_diff_artifact += "-jitoption", o + if self.coreclr_args.jitoption: + for o in self.coreclr_args.jitoption: + diff_option_flags += "-jit2option", o + diff_option_flags_for_diff_artifact += "-jitoption", o if self.coreclr_args.altjit: altjit_asm_diffs_flags += [ @@ -3376,6 +3385,11 @@ def verify_base_diff_args(): lambda unused: True, "Unable to set base_git_hash") + coreclr_args.verify(args, + "jitoption", + lambda unused: True, + "Unable to set jitoption") + coreclr_args.verify(args, "base_jit_option", lambda unused: True, diff --git a/src/coreclr/scripts/superpmi_aspnet.py b/src/coreclr/scripts/superpmi_aspnet.py index e2aeecf2a478d..03f8757a702c9 100644 --- a/src/coreclr/scripts/superpmi_aspnet.py +++ b/src/coreclr/scripts/superpmi_aspnet.py @@ -132,8 +132,8 @@ def build_and_run(coreclr_args): print ("Executing in " + temp_location) - # install dotnet 5.0 - run_command([dotnet_install_script_path, "-Version", "5.0.3"], temp_location, _exit_on_fail=True) + # install dotnet 6.0 + run_command([dotnet_install_script_path, "-Version", "6.0.4"], temp_location, _exit_on_fail=True) os.environ['DOTNET_MULTILEVEL_LOOKUP'] = '0' os.environ['DOTNET_SKIP_FIRST_TIME_EXPERIENCE'] = '1' dotnet_path = path.join(source_directory, ".dotnet") diff --git a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs index 0c4b0e1684473..549d8fbd290b2 100644 --- a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs +++ b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs @@ -12,7 +12,7 @@ namespace ILCompiler { - internal static class DisplayNameHelpers + public static class DisplayNameHelpers { public static string GetDisplayName(this TypeSystemEntity entity) { diff --git a/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs b/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs index dd34d85aaa569..a225665dcee12 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/EETypeBuilderHelpers.cs @@ -121,7 +121,7 @@ internal static uint ComputeValueTypeFieldPaddingFieldValue(uint padding, uint a while ((alignment & 1) == 0) { alignmentLog2++; - alignment = alignment >> 1; + alignment >>= 1; } Debug.Assert(alignment == 1); diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index 30d8af4efb23c..d9671ef058ae1 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -15,7 +15,7 @@ internal struct ReadyToRunHeaderConstants public const uint Signature = 0x00525452; // 'RTR' public const ushort CurrentMajorVersion = 6; - public const ushort CurrentMinorVersion = 1; + public const ushort CurrentMinorVersion = 2; } #pragma warning disable 0169 diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index fa7a9f8688d50..c618b88859585 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -100,6 +100,20 @@ static CorInfoInline _canInline(IntPtr thisHandle, IntPtr* ppException, CORINFO_ } } + [UnmanagedCallersOnly] + static void _beginInlining(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + var _this = GetThis(thisHandle); + try + { + _this.beginInlining(inlinerHnd, inlineeHnd); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] static void _reportInliningDecision(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) { @@ -2552,7 +2566,7 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_FLAGS* f static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 173); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2560,172 +2574,173 @@ static IntPtr GetUnmanagedCallbacks() callbacks[3] = (delegate* unmanaged)&_getMethodSig; callbacks[4] = (delegate* unmanaged)&_getMethodInfo; callbacks[5] = (delegate* unmanaged)&_canInline; - callbacks[6] = (delegate* unmanaged)&_reportInliningDecision; - callbacks[7] = (delegate* unmanaged)&_canTailCall; - callbacks[8] = (delegate* unmanaged)&_reportTailCallDecision; - callbacks[9] = (delegate* unmanaged)&_getEHinfo; - callbacks[10] = (delegate* unmanaged)&_getMethodClass; - callbacks[11] = (delegate* unmanaged)&_getMethodModule; - callbacks[12] = (delegate* unmanaged)&_getMethodVTableOffset; - callbacks[13] = (delegate* unmanaged)&_resolveVirtualMethod; - callbacks[14] = (delegate* unmanaged)&_getUnboxedEntry; - callbacks[15] = (delegate* unmanaged)&_getDefaultComparerClass; - callbacks[16] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; - callbacks[17] = (delegate* unmanaged)&_expandRawHandleIntrinsic; - callbacks[18] = (delegate* unmanaged)&_isIntrinsicType; - callbacks[19] = (delegate* unmanaged)&_getUnmanagedCallConv; - callbacks[20] = (delegate* unmanaged)&_pInvokeMarshalingRequired; - callbacks[21] = (delegate* unmanaged)&_satisfiesMethodConstraints; - callbacks[22] = (delegate* unmanaged)&_isCompatibleDelegate; - callbacks[23] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; - callbacks[24] = (delegate* unmanaged)&_mapMethodDeclToMethodImpl; - callbacks[25] = (delegate* unmanaged)&_getGSCookie; - callbacks[26] = (delegate* unmanaged)&_setPatchpointInfo; - callbacks[27] = (delegate* unmanaged)&_getOSRInfo; - callbacks[28] = (delegate* unmanaged)&_resolveToken; - callbacks[29] = (delegate* unmanaged)&_tryResolveToken; - callbacks[30] = (delegate* unmanaged)&_findSig; - callbacks[31] = (delegate* unmanaged)&_findCallSiteSig; - callbacks[32] = (delegate* unmanaged)&_getTokenTypeAsHandle; - callbacks[33] = (delegate* unmanaged)&_isValidToken; - callbacks[34] = (delegate* unmanaged)&_isValidStringRef; - callbacks[35] = (delegate* unmanaged)&_getStringLiteral; - callbacks[36] = (delegate* unmanaged)&_asCorInfoType; - callbacks[37] = (delegate* unmanaged)&_getClassName; - callbacks[38] = (delegate* unmanaged)&_getClassNameFromMetadata; - callbacks[39] = (delegate* unmanaged)&_getTypeInstantiationArgument; - callbacks[40] = (delegate* unmanaged)&_appendClassName; - callbacks[41] = (delegate* unmanaged)&_isValueClass; - callbacks[42] = (delegate* unmanaged)&_canInlineTypeCheck; - callbacks[43] = (delegate* unmanaged)&_getClassAttribs; - callbacks[44] = (delegate* unmanaged)&_getClassModule; - callbacks[45] = (delegate* unmanaged)&_getModuleAssembly; - callbacks[46] = (delegate* unmanaged)&_getAssemblyName; - callbacks[47] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[48] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[49] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[50] = (delegate* unmanaged)&_getClassSize; - callbacks[51] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[52] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[53] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[54] = (delegate* unmanaged)&_getClassGClayout; - callbacks[55] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[56] = (delegate* unmanaged)&_getFieldInClass; - callbacks[57] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[58] = (delegate* unmanaged)&_getNewHelper; - callbacks[59] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[60] = (delegate* unmanaged)&_getCastingHelper; - callbacks[61] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[62] = (delegate* unmanaged)&_getTypeForBox; - callbacks[63] = (delegate* unmanaged)&_getBoxHelper; - callbacks[64] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[66] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[67] = (delegate* unmanaged)&_getHelperName; - callbacks[68] = (delegate* unmanaged)&_initClass; - callbacks[69] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[70] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[71] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[72] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[73] = (delegate* unmanaged)&_canCast; - callbacks[74] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[75] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[76] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[77] = (delegate* unmanaged)&_mergeClasses; - callbacks[78] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[79] = (delegate* unmanaged)&_getParentType; - callbacks[80] = (delegate* unmanaged)&_getChildType; - callbacks[81] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[82] = (delegate* unmanaged)&_isSDArray; - callbacks[83] = (delegate* unmanaged)&_getArrayRank; - callbacks[84] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[85] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[86] = (delegate* unmanaged)&_canAccessClass; - callbacks[87] = (delegate* unmanaged)&_getFieldName; - callbacks[88] = (delegate* unmanaged)&_getFieldClass; - callbacks[89] = (delegate* unmanaged)&_getFieldType; - callbacks[90] = (delegate* unmanaged)&_getFieldOffset; - callbacks[91] = (delegate* unmanaged)&_getFieldInfo; - callbacks[92] = (delegate* unmanaged)&_isFieldStatic; - callbacks[93] = (delegate* unmanaged)&_getBoundaries; - callbacks[94] = (delegate* unmanaged)&_setBoundaries; - callbacks[95] = (delegate* unmanaged)&_getVars; - callbacks[96] = (delegate* unmanaged)&_setVars; - callbacks[97] = (delegate* unmanaged)&_allocateArray; - callbacks[98] = (delegate* unmanaged)&_freeArray; - callbacks[99] = (delegate* unmanaged)&_getArgNext; - callbacks[100] = (delegate* unmanaged)&_getArgType; - callbacks[101] = (delegate* unmanaged)&_getArgClass; - callbacks[102] = (delegate* unmanaged)&_getHFAType; - callbacks[103] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[104] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[105] = (delegate* unmanaged)&_FilterException; - callbacks[106] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[107] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[108] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[109] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[110] = (delegate* unmanaged)&_getEEInfo; - callbacks[111] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[112] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[113] = (delegate* unmanaged)&_getMethodName; - callbacks[114] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[115] = (delegate* unmanaged)&_getMethodHash; - callbacks[116] = (delegate* unmanaged)&_findNameOfToken; - callbacks[117] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[118] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[119] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[120] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[121] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[122] = (delegate* unmanaged)&_getHelperFtn; - callbacks[123] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[124] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[125] = (delegate* unmanaged)&_getMethodSync; - callbacks[126] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[127] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[128] = (delegate* unmanaged)&_embedClassHandle; - callbacks[129] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[130] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[131] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[132] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[133] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[134] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[135] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[136] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[137] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[138] = (delegate* unmanaged)&_getCallInfo; - callbacks[139] = (delegate* unmanaged)&_canAccessFamily; - callbacks[140] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[141] = (delegate* unmanaged)&_getClassDomainID; - callbacks[142] = (delegate* unmanaged)&_getFieldAddress; - callbacks[143] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[144] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[145] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[146] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[147] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[148] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[149] = (delegate* unmanaged)&_addActiveDependency; - callbacks[150] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[151] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[152] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[153] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[154] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[155] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[156] = (delegate* unmanaged)&_allocMem; - callbacks[157] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[158] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[159] = (delegate* unmanaged)&_allocGCInfo; - callbacks[160] = (delegate* unmanaged)&_setEHcount; - callbacks[161] = (delegate* unmanaged)&_setEHinfo; - callbacks[162] = (delegate* unmanaged)&_logMsg; - callbacks[163] = (delegate* unmanaged)&_doAssert; - callbacks[164] = (delegate* unmanaged)&_reportFatalError; - callbacks[165] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[166] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[167] = (delegate* unmanaged)&_recordCallSite; - callbacks[168] = (delegate* unmanaged)&_recordRelocation; - callbacks[169] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[170] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[171] = (delegate* unmanaged)&_getJitFlags; + callbacks[6] = (delegate* unmanaged)&_beginInlining; + callbacks[7] = (delegate* unmanaged)&_reportInliningDecision; + callbacks[8] = (delegate* unmanaged)&_canTailCall; + callbacks[9] = (delegate* unmanaged)&_reportTailCallDecision; + callbacks[10] = (delegate* unmanaged)&_getEHinfo; + callbacks[11] = (delegate* unmanaged)&_getMethodClass; + callbacks[12] = (delegate* unmanaged)&_getMethodModule; + callbacks[13] = (delegate* unmanaged)&_getMethodVTableOffset; + callbacks[14] = (delegate* unmanaged)&_resolveVirtualMethod; + callbacks[15] = (delegate* unmanaged)&_getUnboxedEntry; + callbacks[16] = (delegate* unmanaged)&_getDefaultComparerClass; + callbacks[17] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; + callbacks[18] = (delegate* unmanaged)&_expandRawHandleIntrinsic; + callbacks[19] = (delegate* unmanaged)&_isIntrinsicType; + callbacks[20] = (delegate* unmanaged)&_getUnmanagedCallConv; + callbacks[21] = (delegate* unmanaged)&_pInvokeMarshalingRequired; + callbacks[22] = (delegate* unmanaged)&_satisfiesMethodConstraints; + callbacks[23] = (delegate* unmanaged)&_isCompatibleDelegate; + callbacks[24] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; + callbacks[25] = (delegate* unmanaged)&_mapMethodDeclToMethodImpl; + callbacks[26] = (delegate* unmanaged)&_getGSCookie; + callbacks[27] = (delegate* unmanaged)&_setPatchpointInfo; + callbacks[28] = (delegate* unmanaged)&_getOSRInfo; + callbacks[29] = (delegate* unmanaged)&_resolveToken; + callbacks[30] = (delegate* unmanaged)&_tryResolveToken; + callbacks[31] = (delegate* unmanaged)&_findSig; + callbacks[32] = (delegate* unmanaged)&_findCallSiteSig; + callbacks[33] = (delegate* unmanaged)&_getTokenTypeAsHandle; + callbacks[34] = (delegate* unmanaged)&_isValidToken; + callbacks[35] = (delegate* unmanaged)&_isValidStringRef; + callbacks[36] = (delegate* unmanaged)&_getStringLiteral; + callbacks[37] = (delegate* unmanaged)&_asCorInfoType; + callbacks[38] = (delegate* unmanaged)&_getClassName; + callbacks[39] = (delegate* unmanaged)&_getClassNameFromMetadata; + callbacks[40] = (delegate* unmanaged)&_getTypeInstantiationArgument; + callbacks[41] = (delegate* unmanaged)&_appendClassName; + callbacks[42] = (delegate* unmanaged)&_isValueClass; + callbacks[43] = (delegate* unmanaged)&_canInlineTypeCheck; + callbacks[44] = (delegate* unmanaged)&_getClassAttribs; + callbacks[45] = (delegate* unmanaged)&_getClassModule; + callbacks[46] = (delegate* unmanaged)&_getModuleAssembly; + callbacks[47] = (delegate* unmanaged)&_getAssemblyName; + callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; + callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; + callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; + callbacks[51] = (delegate* unmanaged)&_getClassSize; + callbacks[52] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[53] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[54] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[55] = (delegate* unmanaged)&_getClassGClayout; + callbacks[56] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[57] = (delegate* unmanaged)&_getFieldInClass; + callbacks[58] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[59] = (delegate* unmanaged)&_getNewHelper; + callbacks[60] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[61] = (delegate* unmanaged)&_getCastingHelper; + callbacks[62] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[63] = (delegate* unmanaged)&_getTypeForBox; + callbacks[64] = (delegate* unmanaged)&_getBoxHelper; + callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[66] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[67] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[68] = (delegate* unmanaged)&_getHelperName; + callbacks[69] = (delegate* unmanaged)&_initClass; + callbacks[70] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[71] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[72] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[73] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[74] = (delegate* unmanaged)&_canCast; + callbacks[75] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[76] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[77] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[78] = (delegate* unmanaged)&_mergeClasses; + callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[80] = (delegate* unmanaged)&_getParentType; + callbacks[81] = (delegate* unmanaged)&_getChildType; + callbacks[82] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[83] = (delegate* unmanaged)&_isSDArray; + callbacks[84] = (delegate* unmanaged)&_getArrayRank; + callbacks[85] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[86] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[87] = (delegate* unmanaged)&_canAccessClass; + callbacks[88] = (delegate* unmanaged)&_getFieldName; + callbacks[89] = (delegate* unmanaged)&_getFieldClass; + callbacks[90] = (delegate* unmanaged)&_getFieldType; + callbacks[91] = (delegate* unmanaged)&_getFieldOffset; + callbacks[92] = (delegate* unmanaged)&_getFieldInfo; + callbacks[93] = (delegate* unmanaged)&_isFieldStatic; + callbacks[94] = (delegate* unmanaged)&_getBoundaries; + callbacks[95] = (delegate* unmanaged)&_setBoundaries; + callbacks[96] = (delegate* unmanaged)&_getVars; + callbacks[97] = (delegate* unmanaged)&_setVars; + callbacks[98] = (delegate* unmanaged)&_allocateArray; + callbacks[99] = (delegate* unmanaged)&_freeArray; + callbacks[100] = (delegate* unmanaged)&_getArgNext; + callbacks[101] = (delegate* unmanaged)&_getArgType; + callbacks[102] = (delegate* unmanaged)&_getArgClass; + callbacks[103] = (delegate* unmanaged)&_getHFAType; + callbacks[104] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[105] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[106] = (delegate* unmanaged)&_FilterException; + callbacks[107] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[108] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[109] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[110] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[111] = (delegate* unmanaged)&_getEEInfo; + callbacks[112] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[113] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[114] = (delegate* unmanaged)&_getMethodName; + callbacks[115] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[116] = (delegate* unmanaged)&_getMethodHash; + callbacks[117] = (delegate* unmanaged)&_findNameOfToken; + callbacks[118] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[119] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[120] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[121] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[122] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[123] = (delegate* unmanaged)&_getHelperFtn; + callbacks[124] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[125] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[126] = (delegate* unmanaged)&_getMethodSync; + callbacks[127] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[128] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[129] = (delegate* unmanaged)&_embedClassHandle; + callbacks[130] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[131] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[132] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[133] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[134] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[135] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[136] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[137] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[138] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[139] = (delegate* unmanaged)&_getCallInfo; + callbacks[140] = (delegate* unmanaged)&_canAccessFamily; + callbacks[141] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[142] = (delegate* unmanaged)&_getClassDomainID; + callbacks[143] = (delegate* unmanaged)&_getFieldAddress; + callbacks[144] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[145] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[146] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[147] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[148] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[149] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[150] = (delegate* unmanaged)&_addActiveDependency; + callbacks[151] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[152] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[153] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[154] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[155] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[156] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[157] = (delegate* unmanaged)&_allocMem; + callbacks[158] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[159] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[160] = (delegate* unmanaged)&_allocGCInfo; + callbacks[161] = (delegate* unmanaged)&_setEHcount; + callbacks[162] = (delegate* unmanaged)&_setEHinfo; + callbacks[163] = (delegate* unmanaged)&_logMsg; + callbacks[164] = (delegate* unmanaged)&_doAssert; + callbacks[165] = (delegate* unmanaged)&_reportFatalError; + callbacks[166] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[167] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[168] = (delegate* unmanaged)&_recordCallSite; + callbacks[169] = (delegate* unmanaged)&_recordRelocation; + callbacks[170] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[171] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[172] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index b6d7649864b99..3bb774ed11b50 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -286,9 +286,14 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint + CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted. + CORINFO_HELP_CLASSPROFILE32, // Update 32-bit class profile for a call site CORINFO_HELP_CLASSPROFILE64, // Update 64-bit class profile for a call site - CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted. + CORINFO_HELP_DELEGATEPROFILE32, // Update 32-bit method profile for a delegate call site + CORINFO_HELP_DELEGATEPROFILE64, // Update 64-bit method profile for a delegate call site + CORINFO_HELP_VTABLEPROFILE32, // Update 32-bit method profile for a vtable call site + CORINFO_HELP_VTABLEPROFILE64, // Update 64-bit method profile for a vtable call site CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index bb822b4655506..27dbbfb44b9f8 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -101,20 +101,23 @@ public static IntPtr Get() private static readonly IntPtr s_jit; } - private struct LikelyClassRecord + private struct LikelyClassMethodRecord { - public IntPtr clsHandle; + public IntPtr handle; public uint likelihood; - public LikelyClassRecord(IntPtr clsHandle, uint likelihood) + public LikelyClassMethodRecord(IntPtr handle, uint likelihood) { - this.clsHandle = clsHandle; + this.handle = handle; this.likelihood = likelihood; } } [DllImport(JitLibrary)] - private extern static uint getLikelyClasses(LikelyClassRecord* pLikelyClasses, uint maxLikelyClasses, PgoInstrumentationSchema* schema, uint countSchemaItems, byte*pInstrumentationData, int ilOffset); + private extern static uint getLikelyClasses(LikelyClassMethodRecord* pLikelyClasses, uint maxLikelyClasses, PgoInstrumentationSchema* schema, uint countSchemaItems, byte*pInstrumentationData, int ilOffset); + + [DllImport(JitLibrary)] + private extern static uint getLikelyMethods(LikelyClassMethodRecord* pLikelyMethods, uint maxLikelyMethods, PgoInstrumentationSchema* schema, uint countSchemaItems, byte*pInstrumentationData, int ilOffset); [DllImport(JitSupportLibrary)] private extern static IntPtr GetJitHost(IntPtr configProvider); @@ -192,17 +195,18 @@ private Logger Logger public static IEnumerable ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(PgoSchemaElem[] pgoData, CompilationModuleGroup compilationModuleGroup) { - bool hasTypeHistogram = false; + bool hasHistogram = false; foreach (var elem in pgoData) { - if (elem.InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes) + if (elem.InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes || + elem.InstrumentationKind == PgoInstrumentationKind.HandleHistogramMethods) { // found histogram - hasTypeHistogram = true; + hasHistogram = true; break; } } - if (!hasTypeHistogram) + if (!hasHistogram) { foreach (var elem in pgoData) { @@ -222,9 +226,10 @@ public static IEnumerable ConvertTypeHandleHistogramsToCompactTyp if ((i + 1 < pgoData.Length) && (pgoData[i].InstrumentationKind == PgoInstrumentationKind.HandleHistogramIntCount || pgoData[i].InstrumentationKind == PgoInstrumentationKind.HandleHistogramLongCount) && - (pgoData[i + 1].InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes)) + (pgoData[i + 1].InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes || + pgoData[i + 1].InstrumentationKind == PgoInstrumentationKind.HandleHistogramMethods)) { - PgoSchemaElem? newElem = ComputeLikelyClass(i, handleToObject, nativeSchema, instrumentationData, compilationModuleGroup); + PgoSchemaElem? newElem = ComputeLikelyClassMethod(i, handleToObject, nativeSchema, instrumentationData, compilationModuleGroup); if (newElem.HasValue) { yield return newElem.Value; @@ -249,33 +254,63 @@ IntPtr LocalObjectToHandle(object input) } } - private static PgoSchemaElem? ComputeLikelyClass(int index, Dictionary handleToObject, PgoInstrumentationSchema[] nativeSchema, byte[] instrumentationData, CompilationModuleGroup compilationModuleGroup) + private static PgoSchemaElem? ComputeLikelyClassMethod(int index, Dictionary handleToObject, PgoInstrumentationSchema[] nativeSchema, byte[] instrumentationData, CompilationModuleGroup compilationModuleGroup) { // getLikelyClasses will use two entries from the native schema table. There must be at least two present to avoid overruning the buffer if (index > (nativeSchema.Length - 2)) return null; + bool isType = nativeSchema[index + 1].InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes; + fixed(PgoInstrumentationSchema* pSchema = &nativeSchema[index]) { fixed(byte* pInstrumentationData = &instrumentationData[0]) { - // We're going to store only the most popular type to reduce size of the profile - LikelyClassRecord* likelyClasses = stackalloc LikelyClassRecord[1]; - uint numberOfClasses = getLikelyClasses(likelyClasses, 1, pSchema, 2, pInstrumentationData, nativeSchema[index].ILOffset); + // We're going to store only the most popular type/method to reduce size of the profile + LikelyClassMethodRecord* likelyClassMethods = stackalloc LikelyClassMethodRecord[1]; + uint numberOfRecords; + if (isType) + { + numberOfRecords = getLikelyClasses(likelyClassMethods, 1, pSchema, 2, pInstrumentationData, nativeSchema[index].ILOffset); + } + else + { + numberOfRecords = getLikelyMethods(likelyClassMethods, 1, pSchema, 2, pInstrumentationData, nativeSchema[index].ILOffset); + } - if (numberOfClasses > 0) + if (numberOfRecords > 0) { - TypeDesc type = (TypeDesc)handleToObject[likelyClasses->clsHandle]; + TypeSystemEntityOrUnknown[] newData = null; + if (isType) + { + TypeDesc type = (TypeDesc)handleToObject[likelyClassMethods->handle]; +#if READYTORUN + if (compilationModuleGroup.VersionsWithType(type)) +#endif + { + newData = new[] { new TypeSystemEntityOrUnknown(type) }; + } + } + else + { + MethodDesc method = (MethodDesc)handleToObject[likelyClassMethods->handle]; + #if READYTORUN - if (compilationModuleGroup.VersionsWithType(type)) + if (compilationModuleGroup.VersionsWithMethodBody(method)) #endif + { + newData = new[] { new TypeSystemEntityOrUnknown(method) }; + } + } + + if (newData != null) { PgoSchemaElem likelyClassElem = new PgoSchemaElem(); - likelyClassElem.InstrumentationKind = PgoInstrumentationKind.GetLikelyClass; + likelyClassElem.InstrumentationKind = isType ? PgoInstrumentationKind.GetLikelyClass : PgoInstrumentationKind.GetLikelyMethod; likelyClassElem.ILOffset = nativeSchema[index].ILOffset; likelyClassElem.Count = 1; - likelyClassElem.Other = (int)(likelyClasses->likelihood | (numberOfClasses << 8)); - likelyClassElem.DataObject = new TypeSystemEntityOrUnknown[] { new TypeSystemEntityOrUnknown(type) }; + likelyClassElem.Other = (int)(likelyClassMethods->likelihood | (numberOfRecords << 8)); + likelyClassElem.DataObject = newData; return likelyClassElem; } } @@ -431,7 +466,18 @@ private void PublishCode() _methodCodeNode.InitializeDebugLocInfos(_debugLocInfos); _methodCodeNode.InitializeDebugVarInfos(_debugVarInfos); #if READYTORUN - _methodCodeNode.InitializeInliningInfo(_inlinedMethods.ToArray(), _compilation.NodeFactory); + MethodDesc[] inlineeArray; + if (_inlinedMethods != null) + { + inlineeArray = new MethodDesc[_inlinedMethods.Count]; + _inlinedMethods.CopyTo(inlineeArray); + Array.Sort(inlineeArray, TypeSystemComparer.Instance.Compare); + } + else + { + inlineeArray = Array.Empty(); + } + _methodCodeNode.InitializeInliningInfo(inlineeArray, _compilation.NodeFactory); // Detect cases where the instruction set support used is a superset of the baseline instruction set specification var baselineSupport = _compilation.InstructionSetSupport; @@ -460,7 +506,20 @@ private void PublishCode() InstructionSetSupport actualSupport = new InstructionSetSupport(_actualInstructionSetSupported, _actualInstructionSetUnsupported, architecture); var node = _compilation.SymbolNodeFactory.PerMethodInstructionSetSupportFixup(actualSupport); - _methodCodeNode.Fixups.Add(node); + AddPrecodeFixup(node); + } + + Debug.Assert(_stashedPrecodeFixups.Count == 0); + if (_precodeFixups != null) + { + HashSet computedNodes = new HashSet(); + foreach (var fixup in _precodeFixups) + { + if (computedNodes.Add(fixup)) + { + _methodCodeNode.Fixups.Add(fixup); + } + } } #else var methodIL = (MethodIL)HandleToObject((IntPtr)_methodScope); @@ -566,9 +625,12 @@ private void CompileMethodCleanup() _lastException = null; #if READYTORUN - _inlinedMethods = new ArrayBuilder(); + _inlinedMethods = null; _actualInstructionSetSupported = default(InstructionSetFlags); _actualInstructionSetUnsupported = default(InstructionSetFlags); + _precodeFixups = null; + _stashedPrecodeFixups.Clear(); + _stashedInlinedMethods.Clear(); #endif _instantiationToJitVisibleInstantiation = null; @@ -1381,7 +1443,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout) { ISymbolNode virtualResolutionNode = _compilation.SymbolNodeFactory.CheckVirtualFunctionOverride(methodWithTokenDecl, objType, methodWithTokenImpl); - _methodCodeNode.Fixups.Add(virtualResolutionNode); + AddPrecodeFixup(virtualResolutionNode); } #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; @@ -2084,7 +2146,7 @@ private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) if (NeedsTypeLayoutCheck(type)) { ISymbolNode node = _compilation.SymbolNodeFactory.CheckTypeLayout(type); - _methodCodeNode.Fixups.Add(node); + AddPrecodeFixup(node); } #endif return (uint)classSize.AsInt; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 9a173957fa007..1f65d5e5f8354 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -478,7 +478,11 @@ public enum CorInfoClassId } public enum CorInfoInline { - INLINE_PASS = 0, // Inlining OK + INLINE_PASS = 0, // Inlining OK + INLINE_PREJIT_SUCCESS = 1, // Inline check for prejit checking usage succeeded + INLINE_CHECK_CAN_INLINE_SUCCESS = 2, // JIT detected it is permitted to try to actually inline + INLINE_CHECK_CAN_INLINE_VMFAIL = 3, // VM specified that inline must fail via the CanInline api + // failures are negative INLINE_FAIL = -1, // Inlining not OK for this case only diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 45fcdef14faaf..f1393ad2095a7 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -159,6 +159,7 @@ FUNCTIONS void getMethodSig( CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO *sig, CORINFO_CLASS_HANDLE memberParent ); bool getMethodInfo( CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info ); CorInfoInline canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd); + void beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd); void reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char * reason); bool canTailCall( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE declaredCalleeHnd, CORINFO_METHOD_HANDLE exactCalleeHnd, bool fIsTailPrefix ); void reportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, const char * reason); diff --git a/src/coreclr/tools/Common/Pgo/PgoFormat.cs b/src/coreclr/tools/Common/Pgo/PgoFormat.cs index a4e23286be4c6..5dc847b34810b 100644 --- a/src/coreclr/tools/Common/Pgo/PgoFormat.cs +++ b/src/coreclr/tools/Common/Pgo/PgoFormat.cs @@ -49,6 +49,7 @@ public enum PgoInstrumentationKind EdgeIntCount = (DescriptorMin * 6) | FourByte, // edge counter using unsigned 4 byte int EdgeLongCount = (DescriptorMin * 6) | EightByte, // edge counter using unsigned 8 byte int GetLikelyClass = (DescriptorMin * 7) | TypeHandle, // Compressed get likely class data + GetLikelyMethod = (DescriptorMin * 7) | MethodHandle, // Compressed get likely method data } public interface IPgoSchemaDataLoader diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs b/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs index c537f6ea4571e..838dd7038d33b 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs @@ -233,7 +233,7 @@ private void SetFieldLayout(List fieldLayoutInterval, int o previousInterval.EndSentinel = newInterval.EndSentinel; fieldLayoutInterval[newIntervalLocation - 1] = previousInterval; - newIntervalLocation = newIntervalLocation - 1; + newIntervalLocation--; } else { diff --git a/src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs index ad44d48574795..23bd5ba923a54 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs @@ -45,6 +45,9 @@ public abstract TypeDesc FieldType get; } + // Get the embedded signature data used to hold custom modifiers and such within a field signature + public abstract EmbeddedSignatureData[] GetEmbeddedSignatureData(); + public abstract bool IsStatic { get; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs index b51d55660a686..fbc456a830639 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/FieldForInstantiatedType.cs @@ -51,6 +51,11 @@ public override TypeDesc FieldType } } + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() + { + return _fieldDef.GetEmbeddedSignatureData(); + } + public override bool IsStatic { get diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs index f1164b677e20a..bed4e2388e92a 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs @@ -273,7 +273,7 @@ public static T[] InstantiateTypeArray(T[] uninstantiatedTypes, Instantiation } } - return clone != null ? clone : uninstantiatedTypes; + return clone ?? uninstantiatedTypes; } // Strips instantiation. E.g C -> C diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs index 6b3d37851cee6..5904397c4a015 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeHashingAlgorithms.cs @@ -125,7 +125,7 @@ private static string IntToString(int arg) while (arg != 0) { sb.Append((char)('0' + (arg % 10))); - arg = arg / 10; + arg /= 10; } // Reverse the string diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs index b6d5e4fd41f8b..6ba7907106dd6 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs @@ -113,6 +113,19 @@ public override TypeDesc FieldType } } + // This is extremely rarely needed. Don't cache it at all. + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() + { + var metadataReader = MetadataReader; + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetFieldDefinition(_handle).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader, NotFoundBehavior.Throw); + var fieldType = parser.ParseFieldSignature(out var embeddedSig); + Debug.Assert(fieldType == FieldType); + return embeddedSig; + } + + [MethodImpl(MethodImplOptions.NoInlining)] private int InitializeFieldFlags(int mask) { diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs index 2247f551fc29d..f2530ec8b19d7 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs @@ -471,6 +471,25 @@ public TypeDesc ParseFieldSignature() return ParseType(); } + public TypeDesc ParseFieldSignature(out EmbeddedSignatureData[] embeddedSigData) + { + try + { + _indexStack = new Stack(); + _indexStack.Push(1); + _indexStack.Push(0); + _embeddedSignatureDataList = new List(); + TypeDesc parsedType = ParseFieldSignature(); + embeddedSigData = _embeddedSignatureDataList.Count == 0 ? null : _embeddedSignatureDataList.ToArray(); + return parsedType; + } + finally + { + _indexStack = null; + _embeddedSignatureDataList = null; + } + } + public LocalVariableDefinition[] ParseLocalsSignature() { if (_reader.ReadSignatureHeader().Kind != SignatureKind.LocalVariables) diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs index 073cb7a4fdfb2..2b3b625db32d1 100644 --- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs @@ -374,7 +374,12 @@ public override MethodDesc GetDefaultConstructor() && stringComparer.Equals(methodDefinition.Name, ".ctor")) { var method = (EcmaMethod)_module.GetObject(handle); - if (method.Signature.Length != 0) + MethodSignature sig = method.Signature; + + if (sig.Length != 0) + continue; + + if ((sig.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == MethodSignatureFlags.CallingConventionVarargs) continue; return method; diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeLazyFixupField.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeLazyFixupField.cs index c2a44b01653a5..5b49bfdb50faa 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeLazyFixupField.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeLazyFixupField.cs @@ -56,6 +56,8 @@ public override TypeDesc FieldType } } + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => null; + public override bool HasRva { get diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/InlineArrayType.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/InlineArrayType.cs index 4cf06e8b6bfb4..51ac01f9a2fb6 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/InlineArrayType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/InlineArrayType.cs @@ -441,6 +441,7 @@ public override TypeDesc FieldType return _owningType.ElementType; } } + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => null; public override bool HasRva { diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/NativeStructType.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/NativeStructType.cs index bf5e0c6ef3d7b..149987476b3a3 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/NativeStructType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/NativeStructType.cs @@ -348,6 +348,8 @@ public override TypeDesc FieldType } } + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => null; + public override bool HasRva { get diff --git a/src/coreclr/tools/Common/TypeSystem/MetadataEmitter/TypeSystemMetadataEmitter.cs b/src/coreclr/tools/Common/TypeSystem/MetadataEmitter/TypeSystemMetadataEmitter.cs index 5a47094605c9e..46110f26bb2a8 100644 --- a/src/coreclr/tools/Common/TypeSystem/MetadataEmitter/TypeSystemMetadataEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/MetadataEmitter/TypeSystemMetadataEmitter.cs @@ -18,14 +18,18 @@ class TypeSystemMetadataEmitter MetadataBuilder _metadataBuilder; BlobBuilder _ilBuilder; MethodBodyStreamEncoder _methodBodyStream; + Dictionary _assemblyRefNameHandles = new Dictionary(); Dictionary _assemblyRefs = new Dictionary(); Dictionary _typeRefs = new Dictionary(); Dictionary _methodRefs = new Dictionary(); + Dictionary _fieldRefs = new Dictionary(); Blob _mvidFixup; BlobHandle _noArgsVoidReturnStaticMethodSigHandle; + protected TypeSystemContext _typeSystemContext; - public TypeSystemMetadataEmitter(AssemblyName assemblyName, TypeSystemContext context, AssemblyFlags flags = default(AssemblyFlags)) + public TypeSystemMetadataEmitter(AssemblyName assemblyName, TypeSystemContext context, AssemblyFlags flags = default(AssemblyFlags), byte[] publicKeyArray = null, AssemblyHashAlgorithm hashAlgorithm = AssemblyHashAlgorithm.None) { + _typeSystemContext = context; _metadataBuilder = new MetadataBuilder(); _ilBuilder = new BlobBuilder(); _methodBodyStream = new MethodBodyStreamEncoder(_ilBuilder); @@ -33,21 +37,11 @@ class TypeSystemMetadataEmitter if (assemblyName.CultureName != null) throw new ArgumentException("assemblyName"); - if (assemblyName.GetPublicKeyToken() != null) - throw new ArgumentException("assemblyName"); - var mvid = _metadataBuilder.ReserveGuid(); _mvidFixup = mvid.Content; _metadataBuilder.AddModule(0, assemblyNameHandle, mvid.Handle, default(GuidHandle), default(GuidHandle)); - _metadataBuilder.AddAssembly(assemblyNameHandle, assemblyName.Version ?? new Version(0,0,0,0), default(StringHandle), default(BlobHandle), flags, AssemblyHashAlgorithm.None); - - var canonAssemblyNameHandle = _metadataBuilder.GetOrAddString("System.Private.Canon"); - var canonAssemblyRef = _metadataBuilder.AddAssemblyReference(canonAssemblyNameHandle, new Version(0, 0, 0, 0), default(StringHandle), default(BlobHandle), (AssemblyFlags)0, default(BlobHandle)); - var systemStringHandle = _metadataBuilder.GetOrAddString("System"); - var canonStringHandle = _metadataBuilder.GetOrAddString("__Canon"); - var canonTypeRef = _metadataBuilder.AddTypeReference(canonAssemblyRef, systemStringHandle, canonStringHandle); - _typeRefs.Add(context.CanonType, canonTypeRef); + _metadataBuilder.AddAssembly(assemblyNameHandle, assemblyName.Version ?? new Version(0,0,0,0), default(StringHandle), publicKey: publicKeyArray != null ? _metadataBuilder.GetOrAddBlob(publicKeyArray) : default(BlobHandle), flags, AssemblyHashAlgorithm.None); _metadataBuilder.AddTypeDefinition( default(TypeAttributes), @@ -56,7 +50,20 @@ class TypeSystemMetadataEmitter baseType: default(EntityHandle), fieldList: MetadataTokens.FieldDefinitionHandle(1), methodList: MetadataTokens.MethodDefinitionHandle(1)); + } + public void InjectSystemPrivateCanon() + { + var canonAssemblyNameHandle = _metadataBuilder.GetOrAddString("System.Private.Canon"); + var canonAssemblyRef = _metadataBuilder.AddAssemblyReference(canonAssemblyNameHandle, new Version(0, 0, 0, 0), default(StringHandle), default(BlobHandle), (AssemblyFlags)0, default(BlobHandle)); + var systemStringHandle = _metadataBuilder.GetOrAddString("System"); + var canonStringHandle = _metadataBuilder.GetOrAddString("__Canon"); + var canonTypeRef = _metadataBuilder.AddTypeReference(canonAssemblyRef, systemStringHandle, canonStringHandle); + _typeRefs.Add(_typeSystemContext.CanonType, canonTypeRef); + } + + public void AllowUseOfAddGlobalMethod() + { BlobBuilder noArgsNoReturnStaticMethodSig = new BlobBuilder(); BlobEncoder signatureEncoder = new BlobEncoder(noArgsNoReturnStaticMethodSig); @@ -79,6 +86,8 @@ public MethodDefinitionHandle AddGlobalMethod(string name, InstructionEncoder il private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5"); private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201); + public MetadataBuilder Builder => _metadataBuilder; + public void SerializeToStream(Stream peStream) { var peHeaderBuilder = new PEHeaderBuilder(); @@ -91,6 +100,47 @@ public void SerializeToStream(Stream peStream) peBlob.WriteContentTo(peStream); } + // Generate only the metadata blob as a byte[] + public byte[] EmitToMetadataBlob() + { + MetadataRootBuilder metadataRootBuilder = new MetadataRootBuilder(_metadataBuilder); + BlobBuilder metadataBlobBuilder = new BlobBuilder(); + metadataRootBuilder.Serialize(metadataBlobBuilder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0); + + // Clear some variables to catch any caller trying to emit data after writing the output file + _metadataBuilder = null; + + return metadataBlobBuilder.ToArray(); + } + + public AssemblyReferenceHandle GetAssemblyRef(AssemblyName name) + { + if (!_assemblyRefNameHandles.TryGetValue(name.FullName, out var handle)) + { + StringHandle assemblyName = _metadataBuilder.GetOrAddString(name.Name); + StringHandle cultureName = (name.CultureName != null) ? _metadataBuilder.GetOrAddString(name.CultureName) : default(StringHandle); + BlobHandle publicTokenBlob = name.GetPublicKeyToken() != null ? _metadataBuilder.GetOrAddBlob(name.GetPublicKeyToken()) : default(BlobHandle); + AssemblyFlags flags = default(AssemblyFlags); + if (name.Flags.HasFlag(AssemblyNameFlags.Retargetable)) + { + flags |= AssemblyFlags.Retargetable; + } + if (name.ContentType == AssemblyContentType.WindowsRuntime) + { + flags |= AssemblyFlags.WindowsRuntime; + } + + Version version = name.Version; + if (version == null) + version = new Version(0, 0); + + handle = _metadataBuilder.AddAssemblyReference(assemblyName, version, cultureName, publicTokenBlob, flags, default(BlobHandle)); + + _assemblyRefNameHandles[name.FullName] = handle; + } + return handle; + } + public AssemblyReferenceHandle GetAssemblyRef(IAssemblyDesc assemblyDesc) { if (_assemblyRefs.TryGetValue(assemblyDesc, out var handle)) @@ -98,26 +148,50 @@ public AssemblyReferenceHandle GetAssemblyRef(IAssemblyDesc assemblyDesc) return handle; } AssemblyName name = assemblyDesc.GetName(); - StringHandle assemblyName = _metadataBuilder.GetOrAddString(name.Name); - StringHandle cultureName = (name.CultureName != null) ? _metadataBuilder.GetOrAddString(name.CultureName) : default(StringHandle); - BlobHandle publicTokenBlob = name.GetPublicKeyToken() != null ? _metadataBuilder.GetOrAddBlob(name.GetPublicKeyToken()) : default(BlobHandle); - AssemblyFlags flags = default(AssemblyFlags); - if (name.Flags.HasFlag(AssemblyNameFlags.Retargetable)) + var referenceHandle = GetAssemblyRef(name); + _assemblyRefs.Add(assemblyDesc, referenceHandle); + return referenceHandle; + } + + public EntityHandle EmitMetadataHandleForTypeSystemEntity(TypeSystemEntity entity) + { + switch (entity) { - flags |= AssemblyFlags.Retargetable; + case FieldDesc field: return GetFieldRef(field); + case MethodDesc method: return GetMethodRef(method); + case TypeDesc type: return GetTypeRef(type); + case ModuleDesc assembly: return GetAssemblyRef(assembly.Assembly); + case MethodSignature methodSignature: return GetStandaloneSig(methodSignature); + + default: + throw new NotSupportedException(); } - if (name.ContentType == AssemblyContentType.WindowsRuntime) + } + + public IEnumerable> TypeSystemEntitiesKnown + { + get { - flags |= AssemblyFlags.WindowsRuntime; - } + foreach (var item in _typeRefs) + { + yield return new KeyValuePair(item.Key, item.Value); + } - Version version = name.Version; - if (version == null) - version = new Version(0, 0); + foreach (var item in _methodRefs) + { + yield return new KeyValuePair(item.Key, item.Value); + } - var referenceHandle = _metadataBuilder.AddAssemblyReference(assemblyName, version, cultureName, publicTokenBlob, flags, default(BlobHandle)); - _assemblyRefs.Add(assemblyDesc, referenceHandle); - return referenceHandle; + foreach (var item in _fieldRefs) + { + yield return new KeyValuePair(item.Key, item.Value); + } + } + } + + protected virtual EntityHandle GetNonNestedResolutionScope(MetadataType metadataType) + { + return GetAssemblyRef(metadataType.Module.Assembly); } public EntityHandle GetTypeRef(TypeDesc type) @@ -144,7 +218,7 @@ public EntityHandle GetTypeRef(TypeDesc type) if (metadataType.ContainingType == null) { // non-nested type - resolutionScope = GetAssemblyRef(metadataType.Module.Assembly); + resolutionScope = GetNonNestedResolutionScope(metadataType); } else { @@ -166,6 +240,58 @@ public EntityHandle GetTypeRef(TypeDesc type) return typeHandle; } + private BlobHandle GetMethodSignatureBlobHandle(MethodSignature sig) + { + EmbeddedSignatureDataEmitter signatureDataEmitter; + if (sig.HasEmbeddedSignatureData) + { + signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this); + } + else + { + signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton; + } + + BlobBuilder memberRefSig = new BlobBuilder(); + EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter); + + if (!signatureDataEmitter.Complete) + throw new ArgumentException(); + + var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig); + return sigBlob; + } + + private BlobHandle GetFieldSignatureBlobHandle(FieldDesc field) + { + var fieldDef = field.GetTypicalFieldDefinition(); + var embeddedSigData = field.GetEmbeddedSignatureData(); + EmbeddedSignatureDataEmitter signatureDataEmitter; + if (embeddedSigData != null && embeddedSigData.Length != 0) + { + signatureDataEmitter = new EmbeddedSignatureDataEmitter(embeddedSigData, this); + } + else + { + signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton; + } + + BlobBuilder memberRefSig = new BlobBuilder(); + EncodeFieldSignature(memberRefSig, field.FieldType, signatureDataEmitter); + + if (!signatureDataEmitter.Complete) + throw new ArgumentException(); + + var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig); + return sigBlob; + } + + public EntityHandle GetStandaloneSig(MethodSignature sig) + { + var sigBlob = GetMethodSignatureBlobHandle(sig); + return _metadataBuilder.AddStandaloneSignature(sigBlob); + } + public EntityHandle GetMethodRef(MethodDesc method) { if (_methodRefs.TryGetValue(method, out var handle)) @@ -192,24 +318,8 @@ public EntityHandle GetMethodRef(MethodDesc method) EntityHandle typeHandle = GetTypeRef((MetadataType)method.OwningType); StringHandle methodName = _metadataBuilder.GetOrAddString(method.Name); var sig = method.GetTypicalMethodDefinition().Signature; + var sigBlob = GetMethodSignatureBlobHandle(sig); - EmbeddedSignatureDataEmitter signatureDataEmitter; - if (sig.HasEmbeddedSignatureData) - { - signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this); - } - else - { - signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton; - } - - BlobBuilder memberRefSig = new BlobBuilder(); - EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter); - - if (!signatureDataEmitter.Complete) - throw new ArgumentException(); - - var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig); methodHandle = _metadataBuilder.AddMemberReference(typeHandle, methodName, sigBlob); } @@ -217,6 +327,25 @@ public EntityHandle GetMethodRef(MethodDesc method) return methodHandle; } + public EntityHandle GetFieldRef(FieldDesc field) + { + if (_fieldRefs.TryGetValue(field, out var handle)) + { + return handle; + } + + EntityHandle fieldHandle; + + EntityHandle typeHandle = GetTypeRef((MetadataType)field.OwningType); + StringHandle fieldName = _metadataBuilder.GetOrAddString(field.Name); + + var sigBlob = GetFieldSignatureBlobHandle(field.GetTypicalFieldDefinition()); + fieldHandle = _metadataBuilder.AddMemberReference(typeHandle, fieldName, sigBlob); + + _fieldRefs.Add(field, fieldHandle); + return fieldHandle; + } + private void EncodeType(BlobBuilder blobBuilder, TypeDesc type, EmbeddedSignatureDataEmitter signatureDataEmitter) { signatureDataEmitter.Push(); @@ -543,6 +672,15 @@ void EncodeMethodSignature(BlobBuilder signatureBuilder, MethodSignature sig, Em signatureDataEmitter.Pop(); } + void EncodeFieldSignature(BlobBuilder signatureBuilder, TypeDesc fieldType, EmbeddedSignatureDataEmitter signatureDataEmitter) + { + signatureDataEmitter.Push(); + BlobEncoder signatureEncoder = new BlobEncoder(signatureBuilder); + signatureEncoder.FieldSignature(); + EncodeType(signatureBuilder, fieldType, signatureDataEmitter); + signatureDataEmitter.Pop(); + } + public UserStringHandle GetUserStringHandle(string userString) { return _metadataBuilder.GetOrAddUserString(userString); diff --git a/src/coreclr/tools/aot/.editorconfig b/src/coreclr/tools/aot/.editorconfig index 5f1bbfd242997..f5e97a5d50a0d 100644 --- a/src/coreclr/tools/aot/.editorconfig +++ b/src/coreclr/tools/aot/.editorconfig @@ -27,3 +27,84 @@ dotnet_sort_system_directives_first = true csharp_style_expression_bodied_properties = true:none csharp_style_expression_bodied_indexers = true:none csharp_style_expression_bodied_accessors = true:none + +[Mono.Linker.Tests/**.cs] +indent_style = tab +indent_size = 4 +csharp_new_line_before_open_brace = types,methods +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_name_and_open_parenthesis = true +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_before_open_square_brackets = false +csharp_space_after_cast = true + +csharp_indent_switch_labels = false + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +[Mono.Linker.Tests.Cases/**.cs] +indent_style = tab +indent_size = 4 +csharp_new_line_before_open_brace = types,methods +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_name_and_open_parenthesis = true +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_before_open_square_brackets = false +csharp_space_after_cast = true + +csharp_indent_switch_labels = false + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +[Mono.Linker.Tests.Cases.Expectations/**.cs] +indent_style = tab +indent_size = 4 +csharp_new_line_before_open_brace = types,methods +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_name_and_open_parenthesis = true +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_before_open_square_brackets = false +csharp_space_after_cast = true + +csharp_indent_switch_labels = false + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitution.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitution.cs new file mode 100644 index 0000000000000..be138cefa7de1 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitution.cs @@ -0,0 +1,56 @@ +// 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.IL; +using Internal.IL.Stubs; +using Internal.TypeSystem; + +namespace ILCompiler +{ + internal sealed class BodySubstitution + { + private object _value; + + private readonly static object Throw = new object(); + + public readonly static BodySubstitution ThrowingBody = new BodySubstitution(Throw); + public readonly static BodySubstitution EmptyBody = new BodySubstitution(null); + + public object Value + { + get + { + Debug.Assert(_value != Throw); + return _value; + } + } + + private BodySubstitution(object value) => _value = value; + + public static BodySubstitution Create(object value) => new BodySubstitution(value); + public MethodIL EmitIL(MethodDesc method) + { + ILEmitter emit = new ILEmitter(); + ILCodeStream codestream = emit.NewCodeStream(); + + if (_value == Throw) + { + codestream.EmitCallThrowHelper(emit, method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowFeatureBodyRemoved")); + } + else if (_value == null) + { + Debug.Assert(method.Signature.ReturnType.IsVoid); + codestream.Emit(ILOpcode.ret); + } + else + { + Debug.Assert(_value is int); + codestream.EmitLdc((int)_value); + codestream.Emit(ILOpcode.ret); + } + + return emit.Link(method); + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs new file mode 100644 index 0000000000000..3aade53731c65 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs @@ -0,0 +1,172 @@ +// 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.IO; +using System.Reflection.Metadata; +using Internal.TypeSystem; +using System.Xml.XPath; +using System.Globalization; +using System.Linq; + +namespace ILCompiler +{ + internal sealed class BodySubstitutionsParser : ProcessLinkerXmlBase + { + private readonly Dictionary _methodSubstitutions; + private readonly Dictionary _fieldSubstitutions; + + private BodySubstitutionsParser(TypeSystemContext context, Stream documentStream, ManifestResource resource, ModuleDesc resourceAssembly, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) + : base(context, documentStream, resource, resourceAssembly, xmlDocumentLocation, featureSwitchValues) + { + _methodSubstitutions = new Dictionary(); + _fieldSubstitutions = new Dictionary(); + } + + protected override void ProcessAssembly(ModuleDesc assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) + { + ProcessTypes(assembly, nav, warnOnUnresolvedTypes); + } + + // protected override TypeDesc? ProcessExportedType(ExportedType exported, ModuleDesc assembly, XPathNavigator nav) => null; + + protected override bool ProcessTypePattern(string fullname, ModuleDesc assembly, XPathNavigator nav) => false; + + protected override void ProcessType(TypeDesc type, XPathNavigator nav) + { + Debug.Assert(ShouldProcessElement(nav)); + ProcessTypeChildren(type, nav); + } + + protected override void ProcessMethod(TypeDesc type, XPathNavigator methodNav, object customData) + { + string signature = GetSignature(methodNav); + if (string.IsNullOrEmpty(signature)) + return; + + MethodDesc method = FindMethod(type, signature); + if (method == null) + { + // LogWarning(methodNav, DiagnosticId.XmlCouldNotFindMethodOnType, signature, type.GetDisplayName()); + return; + } + + string action = GetAttribute(methodNav, "body"); + switch (action) + { + case "remove": + _methodSubstitutions.Add(method, BodySubstitution.ThrowingBody); + break; + case "stub": + BodySubstitution stubBody; + if (method.Signature.ReturnType.IsVoid) + stubBody = BodySubstitution.EmptyBody; + else + stubBody = BodySubstitution.Create(TryCreateSubstitution(method.Signature.ReturnType, GetAttribute(methodNav, "value"))); + + if (stubBody != null) + { + _methodSubstitutions[method] = stubBody; + } + else + { + // Context.LogWarning ($"Invalid value for '{method.GetDisplayName ()}' stub", 2010, _xmlDocumentLocation); + } + break; + default: + //Context.LogWarning($"Unknown body modification '{action}' for '{method.GetDisplayName()}'", 2011, _xmlDocumentLocation); + break; + } + } + + protected override void ProcessField(TypeDesc type, XPathNavigator fieldNav) + { + string name = GetAttribute(fieldNav, "name"); + if (string.IsNullOrEmpty(name)) + return; + + var field = type.GetFields().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)) + { + //Context.LogWarning($"Missing 'value' attribute for field '{field.GetDisplayName()}'.", 2014, _xmlDocumentLocation); + return; + } + + object substitution = TryCreateSubstitution(field.FieldType, value); + if (substitution == null) + { + //Context.LogWarning($"Invalid value '{value}' for '{field.GetDisplayName()}'.", 2015, _xmlDocumentLocation); + return; + } + + if (String.Equals(GetAttribute(fieldNav, "initialize"), "true", StringComparison.InvariantCultureIgnoreCase)) + { + // We would need to also mess with the cctor of the type to set the field to this value: + // + // * Linker will remove all stsfld instructions referencing this field from the cctor + // * It will place an explicit stsfld in front of the last "ret" instruction in the cctor + // + // This approach... has issues. + throw new NotSupportedException(); + } + + _fieldSubstitutions[field] = substitution; + } + + static MethodDesc FindMethod(TypeDesc type, string signature) + { + foreach (MethodDesc meth in type.GetMethods()) + if (signature == GetMethodSignature(meth, includeGenericParameters: true)) + return meth; + return null; + } + + private object TryCreateSubstitution(TypeDesc type, string value) + { + switch (type.UnderlyingType.Category) + { + case TypeFlags.Int32: + if (string.IsNullOrEmpty(value)) + return 0; + else if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) + return iresult; + break; + + case TypeFlags.Boolean: + if (String.IsNullOrEmpty(value)) + return 0; + else if (bool.TryParse(value, out bool bvalue)) + return bvalue ? 1 : 0; + else + goto case TypeFlags.Int32; + + default: + throw new NotSupportedException(type.ToString()); + } + + return null; + } + + public static (Dictionary, Dictionary) GetSubstitutions(TypeSystemContext context, UnmanagedMemoryStream documentStream, ManifestResource resource, ModuleDesc resourceAssembly, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) + { + var rdr = new BodySubstitutionsParser(context, documentStream, resource, resourceAssembly, xmlDocumentLocation, featureSwitchValues); + rdr.ProcessXml(false); + return (rdr._methodSubstitutions, rdr._fieldSubstitutions); + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs index 09d58311aee3a..53e443db74447 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs @@ -659,5 +659,12 @@ public sealed class ConstrainedCallInfo public readonly MethodDesc Method; public ConstrainedCallInfo(TypeDesc constrainedType, MethodDesc method) => (ConstrainedType, Method) = (constrainedType, method); + public int CompareTo(ConstrainedCallInfo other, TypeSystemComparer comparer) + { + int result = comparer.Compare(ConstrainedType, other.ConstrainedType); + if (result == 0) + result = comparer.Compare(Method, other.Method); + return result; + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index 3b19dbfcf1ad2..70f3d523ed9e4 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -161,7 +161,9 @@ internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type) { if (!type.IsGenericDefinition && !type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true) && type.HasStaticConstructor) { - _dependencies.Add(_factory.CanonicalEntrypoint(type.GetStaticConstructor()), "RunClassConstructor reference"); + // Mark the GC static base - it contains a pointer to the class constructor, but also info + // about whether the class constructor already executed and it's what is looked at at runtime. + _dependencies.Add(_factory.TypeNonGCStaticsSymbol((MetadataType)type), "RunClassConstructor reference"); } } 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 f584f7c5b2023..18c5b082f60fe 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -597,6 +597,12 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet if (systemTypeValue.RepresentedType.Type.IsDefType) { _reflectionMarker.Dependencies.Add(_factory.StructMarshallingData((DefType)systemTypeValue.RepresentedType.Type), "Marshal API"); + if (intrinsicId == IntrinsicId.Marshal_PtrToStructure + && systemTypeValue.RepresentedType.Type.GetParameterlessConstructor() is MethodDesc ctorMethod + && !_factory.MetadataManager.IsReflectionBlocked(ctorMethod)) + { + _reflectionMarker.Dependencies.Add(_factory.ReflectableMethod(ctorMethod), "Marshal API"); + } } } else @@ -619,7 +625,7 @@ public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMet && !systemTypeValue.RepresentedType.Type.IsGenericDefinition && !systemTypeValue.RepresentedType.Type.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true)) { - if (systemTypeValue.RepresentedType.Type.IsDefType) + if (systemTypeValue.RepresentedType.Type.IsDelegate) { _reflectionMarker.Dependencies.Add(_factory.DelegateMarshallingData((DefType)systemTypeValue.RepresentedType.Type), "Marshal API"); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 845fe201486d3..e2df7d38798e3 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -77,6 +77,11 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType.NormalizeInstantiation()) : null; } + protected override ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) + { + return factory.ConstructedTypeSymbol(((ArrayType)_type).ElementType); + } + protected override int GCDescSize { get diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index 4c5d630437a3b..be5ce0d0dc80b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -101,6 +101,11 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.ConstructedTypeSymbol(_type.BaseType) : null; } + protected override ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) + { + return factory.ConstructedTypeSymbol(((ArrayType)_type).ElementType); + } + protected override IEETypeNode GetInterfaceTypeNode(NodeFactory factory, TypeDesc interfaceType) { // The interface type will be visible to reflection and should be considered constructed. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs index 09111876ceca6..3a8a1438b2bf2 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs @@ -168,7 +168,8 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend { if (decodedArgument.Kind == CustomAttributeNamedArgumentKind.Field) { - // This is an instance field. We don't track them right now. + if (!AddDependenciesFromField(dependencies, factory, attributeType, decodedArgument.Name)) + return false; } else { @@ -186,6 +187,29 @@ private static bool AddDependenciesFromCustomAttributeBlob(DependencyList depend return true; } + private static bool AddDependenciesFromField(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string fieldName) + { + FieldDesc field = attributeType.GetField(fieldName); + if (field is not null) + { + if (factory.MetadataManager.IsReflectionBlocked(field)) + return false; + + dependencies.Add(factory.ReflectableField(field), "Custom attribute blob"); + + return true; + } + + // Haven't found it in current type. Check the base type. + TypeDesc baseType = attributeType.BaseType; + + if (baseType != null) + return AddDependenciesFromField(dependencies, factory, baseType, fieldName); + + // Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation. + return true; + } + private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName) { EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index 0ec69a4f29f76..54b6424032c5b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -757,14 +757,29 @@ protected virtual ISymbolNode GetBaseTypeNode(NodeFactory factory) return _type.BaseType != null ? factory.NecessaryTypeSymbol(_type.BaseType) : null; } + protected virtual ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory) + { + return factory.NecessaryTypeSymbol(((ArrayType)_type).ElementType); + } + private ISymbolNode GetRelatedTypeNode(NodeFactory factory) { ISymbolNode relatedTypeNode = null; - if (_type.IsArray || _type.IsPointer || _type.IsByRef) + if (_type.IsParameterizedType) { var parameterType = ((ParameterizedType)_type).ParameterType; - relatedTypeNode = factory.NecessaryTypeSymbol(parameterType); + if (_type.IsArray && parameterType.IsValueType && !parameterType.IsNullable) + { + // This might be a constructed type symbol. There are APIs on Array that allow allocating element + // types through runtime magic ("((Array)new NeverAllocated[1]).GetValue(0)" or IEnumerable) and we don't have + // visibility into that. Conservatively assume element types of constructed arrays are also constructed. + relatedTypeNode = GetNonNullableValueTypeArrayElementTypeNode(factory); + } + else + { + relatedTypeNode = factory.NecessaryTypeSymbol(parameterType); + } } else { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs index 8f701ceb236d3..603f7c7068fdc 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs @@ -41,7 +41,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto } protected override string GetName(NodeFactory factory) { - return "Reflectable field: " + _field.ToString(); + return "Field metadata: " + _field.ToString(); } protected override void OnMarked(NodeFactory factory) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs index 0272852f07606..d4f419c1b424d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs @@ -19,6 +19,7 @@ public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolN public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager) { Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific)); + Debug.Assert(!type.IsGenericDefinition); _type = type; if (preinitManager.IsPreinitialized(type)) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDictionaryNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDictionaryNode.cs index a824363f9862f..4b821e7865451 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDictionaryNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDictionaryNode.cs @@ -7,6 +7,8 @@ using Internal.Text; using Internal.TypeSystem; +using CombinedDependencyList = System.Collections.Generic.List.CombinedDependencyListEntry>; + namespace ILCompiler.DependencyAnalysis { /// @@ -196,6 +198,13 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde protected override TypeSystemContext Context => _owningMethod.Context; public override TypeSystemEntity OwningEntity => _owningMethod; public MethodDesc OwningMethod => _owningMethod; + public override bool HasConditionalStaticDependencies => true; + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) + { + CombinedDependencyList list = null; + factory.MetadataManager.GetConditionalDependenciesDueToMethodGenericDictionary(ref list, factory, _owningMethod); + return list ?? (IEnumerable)System.Array.Empty(); + } protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs index 8f1269d8fdfa3..427b589090fae 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs @@ -49,7 +49,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto } protected override string GetName(NodeFactory factory) { - return "Reflectable method: " + _method.ToString(); + return "Method metadata: " + _method.ToString(); } protected override void OnMarked(NodeFactory factory) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index 6597476d51cab..54efc8c15c026 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -294,6 +294,11 @@ private void CreateNodeCaches() return new ReflectableMethodNode(method); }); + _reflectableFields = new NodeCache(field => + { + return new ReflectableFieldNode(field); + }); + _objectGetTypeFlowDependencies = new NodeCache(type => { return new ObjectGetTypeFlowDependenciesNode(type); @@ -852,6 +857,12 @@ public ReflectableMethodNode ReflectableMethod(MethodDesc method) return _reflectableMethods.GetOrAdd(method); } + private NodeCache _reflectableFields; + public ReflectableFieldNode ReflectableField(FieldDesc field) + { + return _reflectableFields.GetOrAdd(field); + } + private NodeCache _objectGetTypeFlowDependencies; internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NonGCStaticsNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NonGCStaticsNode.cs index 2e52019a1e153..3c06c90b3c144 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NonGCStaticsNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NonGCStaticsNode.cs @@ -25,6 +25,7 @@ public class NonGCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymb public NonGCStaticsNode(MetadataType type, PreinitializationManager preinitializationManager) { Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific)); + Debug.Assert(!type.IsGenericDefinition); _type = type; _preinitializationManager = preinitializationManager; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index 9ec56a6273359..87ffbb0217d5e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -304,6 +304,8 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer return comparer.Compare((FieldDesc)_target, (FieldDesc)((ReadyToRunGenericHelperNode)other)._target); case ReadyToRunHelperId.DelegateCtor: return ((DelegateCreationInfo)_target).CompareTo((DelegateCreationInfo)((ReadyToRunGenericHelperNode)other)._target, comparer); + case ReadyToRunHelperId.ConstrainedDirectCall: + return ((ConstrainedCallInfo)_target).CompareTo((ConstrainedCallInfo)((ReadyToRunGenericHelperNode)other)._target, comparer); default: throw new NotImplementedException(); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectableFieldNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectableFieldNode.cs new file mode 100644 index 0000000000000..c5bd494505067 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectableFieldNode.cs @@ -0,0 +1,105 @@ +// 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 ILCompiler.DependencyAnalysisFramework; + +using Internal.TypeSystem; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents a field that is gettable/settable from reflection. + /// + public class ReflectableFieldNode : DependencyNodeCore + { + private readonly FieldDesc _field; + + public ReflectableFieldNode(FieldDesc field) + { + Debug.Assert(!field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any) + || field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific) == field.OwningType); + _field = field; + } + + public FieldDesc Field => _field; + + public override IEnumerable GetStaticDependencies(NodeFactory factory) + { + Debug.Assert(!factory.MetadataManager.IsReflectionBlocked(_field.GetTypicalFieldDefinition())); + + DependencyList dependencies = new DependencyList(); + factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, _field); + + // No runtime artifacts needed if this is a generic definition or literal field + if (_field.OwningType.IsGenericDefinition || _field.IsLiteral) + { + return dependencies; + } + + FieldDesc typicalField = _field.GetTypicalFieldDefinition(); + if (typicalField != _field) + { + // Ensure we consistently apply reflectability to all fields sharing the same definition. + // Bases for different instantiations of the field have a conditional dependency on the definition node that + // brings a ReflectableField of the instantiated field if it's necessary for it to be reflectable. + dependencies.Add(factory.ReflectableField(typicalField), "Definition of the reflectable field"); + } + + // Runtime reflection stack needs to see the type handle of the owning type + dependencies.Add(factory.MaximallyConstructableType(_field.OwningType), "Instance base of a reflectable field"); + + // Root the static base of the type + if (_field.IsStatic && !_field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // Infrastructure around static constructors is stashed in the NonGC static base + bool needsNonGcStaticBase = factory.PreinitializationManager.HasLazyStaticConstructor(Field.OwningType); + + if (_field.HasRva) + { + // No reflection access right now + } + else if (_field.IsThreadStatic) + { + dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)_field.OwningType), "Threadstatic base of a reflectable field"); + } + else if (_field.HasGCStaticBase) + { + dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)_field.OwningType), "GC static base of a reflectable field"); + } + else + { + dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "NonGC static base of a reflectable field"); + needsNonGcStaticBase = false; + } + + if (needsNonGcStaticBase) + { + dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_field.OwningType), "CCtor context"); + } + } + + // Runtime reflection stack needs to obtain the type handle of the field + // (but there's no type handles for function pointers) + if (!_field.FieldType.IsFunctionPointer) + dependencies.Add(factory.MaximallyConstructableType(_field.FieldType.NormalizeInstantiation()), "Type of the field"); + + return dependencies; + } + protected override string GetName(NodeFactory factory) + { + return "Reflectable field: " + _field.ToString(); + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool HasDynamicDependencies => false; + public override bool HasConditionalStaticDependencies => false; + public override bool StaticDependenciesAreComputed => true; + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ThreadStaticsNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ThreadStaticsNode.cs index 91733ace5276c..03e318318a7f8 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ThreadStaticsNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ThreadStaticsNode.cs @@ -19,7 +19,8 @@ public class ThreadStaticsNode : EmbeddedObjectNode, ISymbolDefinitionNode public ThreadStaticsNode(MetadataType type, NodeFactory factory) { - Debug.Assert(factory.Target.Abi == TargetAbi.NativeAot || factory.Target.Abi == TargetAbi.CppCodegen); + Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Specific)); + Debug.Assert(!type.IsGenericDefinition); _type = type; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs index e2bff8eb335f2..b81cddee9188c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs @@ -46,11 +46,14 @@ public override IEnumerable GetStaticDependencies(NodeFacto var mdManager = (UsageBasedMetadataManager)factory.MetadataManager; if (_type.IsDelegate) { - // A delegate type metadata is rather useless without the Invoke method. - // If someone reflects on a delegate, chances are they're going to look at the signature. + // We've decided as a policy that delegate Invoke methods will be generated in full. + // The libraries (e.g. System.Linq.Expressions) have trimming warning suppressions + // in places where they assume IL-level trimming (where the method cannot be removed). + // We ask for a full reflectable method with its method body instead of just the + // metadata. var invokeMethod = _type.GetMethod("Invoke", null); if (!mdManager.IsReflectionBlocked(invokeMethod)) - dependencies.Add(factory.MethodMetadata(invokeMethod), "Delegate invoke method metadata"); + dependencies.Add(factory.ReflectableMethod(invokeMethod), "Delegate invoke method"); } if (_type.IsEnum) @@ -58,6 +61,16 @@ public override IEnumerable GetStaticDependencies(NodeFacto // A lot of the enum reflection actually happens on top of the respective MethodTable (e.g. getting the underlying type), // so for enums also include their MethodTable. dependencies.Add(factory.MaximallyConstructableType(_type), "Reflectable enum"); + + // Enums are not useful without their literal fields. The literal fields are not referenced + // from anywhere (source code reference to enums compiles to the underlying numerical constants in IL). + foreach (FieldDesc enumField in _type.GetFields()) + { + if (enumField.IsLiteral) + { + dependencies.Add(factory.FieldMetadata(enumField), "Value of a reflectable enum"); + } + } } // If the user asked for complete metadata to be generated for all types that are getting metadata, ensure that. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExternSymbolMappedField.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExternSymbolMappedField.cs index 2ee25f4dc7c3b..8a4bce713efe4 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExternSymbolMappedField.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ExternSymbolMappedField.cs @@ -26,6 +26,7 @@ public ExternSymbolMappedField(TypeDesc fieldType, string symbolName) public override DefType OwningType => _fieldType.Context.SystemModule.GetGlobalModuleType(); public override TypeDesc FieldType => _fieldType; + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => null; public override bool IsStatic => true; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs index 20050db2c8cda..2efa5cfeb9d1d 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs @@ -8,7 +8,6 @@ using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Xml; - using Internal.IL; using Internal.IL.Stubs; using Internal.TypeSystem; @@ -740,172 +739,10 @@ public AssemblyFeatureInfo(EcmaModule module, IReadOnlyDictionary ms = new UnmanagedMemoryStream(reader.CurrentPointer, length); } - (BodySubstitutions, FieldSubstitutions) = SubstitutionsReader.GetSubstitutions(module.Context, XmlReader.Create(ms), module, featureSwitchValues); + (BodySubstitutions, FieldSubstitutions) = BodySubstitutionsParser.GetSubstitutions(module.Context, ms, resource, module, "name", featureSwitchValues); } } } } - - private class BodySubstitution - { - private object _value; - - private readonly static object Throw = new object(); - - public readonly static BodySubstitution ThrowingBody = new BodySubstitution(Throw); - public readonly static BodySubstitution EmptyBody = new BodySubstitution(null); - - public object Value - { - get - { - Debug.Assert(_value != Throw); - return _value; - } - } - - private BodySubstitution(object value) => _value = value; - - public static BodySubstitution Create(object value) => new BodySubstitution(value); - public MethodIL EmitIL(MethodDesc method) - { - ILEmitter emit = new ILEmitter(); - ILCodeStream codestream = emit.NewCodeStream(); - - if (_value == Throw) - { - codestream.EmitCallThrowHelper(emit, method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowFeatureBodyRemoved")); - } - else if (_value == null) - { - Debug.Assert(method.Signature.ReturnType.IsVoid); - codestream.Emit(ILOpcode.ret); - } - else - { - Debug.Assert(_value is int); - codestream.EmitLdc((int)_value); - codestream.Emit(ILOpcode.ret); - } - - return emit.Link(method); - } - } - - private class SubstitutionsReader : ProcessXmlBase - { - private readonly Dictionary _methodSubstitutions; - private readonly Dictionary _fieldSubstitutions; - - private SubstitutionsReader(TypeSystemContext context, XmlReader reader, ModuleDesc module, IReadOnlyDictionary featureSwitchValues) - : base(context, reader, module, featureSwitchValues) - { - _methodSubstitutions = new Dictionary(); - _fieldSubstitutions = new Dictionary(); - } - - protected override void ProcessMethod(MethodDesc method) - { - string action = GetAttribute("body"); - if (!String.IsNullOrEmpty(action)) - { - switch (action) - { - case "remove": - _methodSubstitutions.Add(method, BodySubstitution.ThrowingBody); - break; - case "stub": - BodySubstitution stubBody; - if (method.Signature.ReturnType.IsVoid) - stubBody = BodySubstitution.EmptyBody; - else - stubBody = BodySubstitution.Create(TryCreateSubstitution(method.Signature.ReturnType, GetAttribute("value"))); - - if (stubBody != null) - { - _methodSubstitutions[method] = stubBody; - } - else - { - // Context.LogWarning ($"Invalid value for '{method.GetDisplayName ()}' stub", 2010, _xmlDocumentLocation); - } - - break; - default: - //Context.LogWarning($"Unknown body modification '{action}' for '{method.GetDisplayName()}'", 2011, _xmlDocumentLocation); - break; - } - } - } - - protected override void ProcessField(FieldDesc field) - { - if (!field.IsStatic || field.IsLiteral) - { - // Context.LogWarning ($"Substituted field '{field.GetDisplayName ()}' needs to be static field.", 2013, _xmlDocumentLocation); - return; - } - - string value = GetAttribute("value"); - if (string.IsNullOrEmpty(value)) - { - //Context.LogWarning($"Missing 'value' attribute for field '{field.GetDisplayName()}'.", 2014, _xmlDocumentLocation); - return; - } - - object substitution = TryCreateSubstitution(field.FieldType, value); - if (substitution == null) - { - //Context.LogWarning($"Invalid value '{value}' for '{field.GetDisplayName()}'.", 2015, _xmlDocumentLocation); - return; - } - - if (String.Equals(GetAttribute("initialize"), "true", StringComparison.InvariantCultureIgnoreCase)) - { - // We would need to also mess with the cctor of the type to set the field to this value: - // - // * Linker will remove all stsfld instructions referencing this field from the cctor - // * It will place an explicit stsfld in front of the last "ret" instruction in the cctor - // - // This approach... has issues. - throw new NotSupportedException(); - } - - _fieldSubstitutions[field] = substitution; - } - - private object TryCreateSubstitution(TypeDesc type, string value) - { - switch (type.UnderlyingType.Category) - { - case TypeFlags.Int32: - if (string.IsNullOrEmpty(value)) - return 0; - else if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult)) - return iresult; - break; - - case TypeFlags.Boolean: - if (String.IsNullOrEmpty(value)) - return 0; - else if (bool.TryParse(value, out bool bvalue)) - return bvalue ? 1 : 0; - else - goto case TypeFlags.Int32; - - default: - throw new NotSupportedException(type.ToString()); - } - - return null; - } - - public static (Dictionary, Dictionary) GetSubstitutions(TypeSystemContext context, XmlReader reader, ModuleDesc module, IReadOnlyDictionary featureSwitchValues) - { - var rdr = new SubstitutionsReader(context, reader, module, featureSwitchValues); - rdr.ProcessXml(); - return (rdr._methodSubstitutions, rdr._fieldSubstitutions); - } - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/IRootingServiceProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/IRootingServiceProvider.cs index adff5b36116e1..c368c762e64ca 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/IRootingServiceProvider.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/IRootingServiceProvider.cs @@ -13,6 +13,7 @@ public interface IRootingServiceProvider void AddCompilationRoot(MethodDesc method, string reason, string exportName = null); void AddCompilationRoot(TypeDesc type, string reason); void AddReflectionRoot(MethodDesc method, string reason); + void AddReflectionRoot(FieldDesc field, string reason); void RootThreadStaticBaseForType(TypeDesc type, string reason); void RootGCStaticBaseForType(TypeDesc type, string reason); void RootNonGCStaticBaseForType(TypeDesc type, string reason); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/GraphBuilder.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/GraphBuilder.cs index 5cdf10665fa28..fd03cb6595787 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/GraphBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LazyGenerics/GraphBuilder.cs @@ -201,8 +201,11 @@ private void WalkMethod(EcmaMethod method) && _metadataReader.GetMemberReference((MemberReferenceHandle)accessedMethod).Parent.Kind == HandleKind.TypeSpecification)) { var m = methodIL.GetObject(MetadataTokens.GetToken(accessedMethod), NotFoundBehavior.ReturnNull) as MethodDesc; - ProcessTypeReference(m.OwningType, typeContext, methodContext); - ProcessMethodCall(m, typeContext, methodContext); + if (m != null) + { + ProcessTypeReference(m.OwningType, typeContext, methodContext); + ProcessMethodCall(m, typeContext, methodContext); + } } break; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs index 5ebf7f1ed3a24..489a13ac271f8 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs @@ -221,6 +221,9 @@ protected virtual void Graph_NewMarkedNode(DependencyNodeCore obj) if (dictionaryNode != null) { _genericDictionariesGenerated.Add(dictionaryNode); + + if (dictionaryNode.OwningEntity is MethodDesc method && AllMethodsCanBeReflectable) + _reflectableMethods.Add(method); } if (obj is StructMarshallingDataNode structMarshallingDataNode) @@ -345,6 +348,19 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies, } } + /// + /// This method is an extension point that can provide additional metadata-based dependencies to generated fields. + /// + public void GetDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field) + { + MetadataCategory category = GetMetadataCategory(field); + + if ((category & MetadataCategory.Description) != 0) + { + GetMetadataDependenciesDueToReflectability(ref dependencies, factory, field); + } + } + /// /// This method is an extension point that can provide additional metadata-based dependencies on a virtual method. /// @@ -359,6 +375,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency // and property setters) } + protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field) + { + // MetadataManagers can override this to provide additional dependencies caused by the emission of metadata + // (E.g. dependencies caused by the field having custom attributes applied to it: making sure we compile the attribute constructor + // and property setters) + } + /// /// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes. /// @@ -371,15 +394,6 @@ public void GetDependenciesDueToReflectability(ref DependencyList dependencies, GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type); } - if ((category & MetadataCategory.RuntimeMapping) != 0) - { - // We're going to generate a mapping table entry for this. Collect dependencies. - - // Nothing special is needed for the mapping table (we only emit the MethodTable and we already - // have one, since we got this callback). But check if a child wants to do something extra. - GetRuntimeMappingDependenciesDueToReflectability(ref dependencies, factory, type); - } - GetDependenciesDueToEETypePresence(ref dependencies, factory, type); } @@ -390,12 +404,6 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency // and property setters) } - protected virtual void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) - { - // MetadataManagers can override this to provide additional dependencies caused by the emission of a runtime - // mapping for a type. - } - protected virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) { // MetadataManagers can override this to provide additional dependencies caused by the emission of an MethodTable. @@ -460,6 +468,12 @@ public void GetDependenciesDueToMethodCodePresence(ref DependencyList dependenci GetDependenciesDueToMethodCodePresenceInternal(ref dependencies, factory, method, methodIL); } + public virtual void GetConditionalDependenciesDueToMethodGenericDictionary(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method) + { + // MetadataManagers can override this to provide additional dependencies caused by the presence of + // method generic dictionary. + } + public virtual void GetConditionalDependenciesDueToMethodCodePresence(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method) { // MetadataManagers can override this to provide additional dependencies caused by the presence of diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs index e4c06223c6c40..062c80897e95f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ProcessLinkerXmlBase.cs @@ -50,7 +50,7 @@ public abstract class ProcessLinkerXmlBase private readonly IReadOnlyDictionary _featureSwitchValues; protected readonly TypeSystemContext _context; - protected ProcessLinkerXmlBase(TypeSystemContext context, UnmanagedMemoryStream documentStream, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) + protected ProcessLinkerXmlBase(TypeSystemContext context, Stream documentStream, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) { _context = context; using (documentStream) @@ -61,7 +61,7 @@ protected ProcessLinkerXmlBase(TypeSystemContext context, UnmanagedMemoryStream _featureSwitchValues = featureSwitchValues; } - protected ProcessLinkerXmlBase(TypeSystemContext context, UnmanagedMemoryStream documentStream, ManifestResource resource, ModuleDesc resourceAssembly, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) + protected ProcessLinkerXmlBase(TypeSystemContext context, Stream documentStream, ManifestResource resource, ModuleDesc resourceAssembly, string xmlDocumentLocation, IReadOnlyDictionary featureSwitchValues) : this(context, documentStream, xmlDocumentLocation, featureSwitchValues) { _owningModule = resourceAssembly ?? throw new ArgumentNullException(nameof(resourceAssembly)); @@ -489,6 +489,31 @@ protected static string GetAttribute(XPathNavigator nav, string attribute) return nav.GetAttribute(attribute, XmlNamespace); } + 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(); + } + #if false protected MessageOrigin GetMessageOriginForPosition(XPathNavigator position) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingHelpers.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingHelpers.cs index cd9cdcf8f7039..987e31fc03c27 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingHelpers.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingHelpers.cs @@ -90,6 +90,11 @@ public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, TryRootMethod(rootProvider, method, reason); } } + + foreach (FieldDesc field in type.GetFields()) + { + TryRootField(rootProvider, field, reason); + } } } @@ -114,6 +119,38 @@ public static void RootMethod(IRootingServiceProvider rootProvider, MethodDesc m rootProvider.AddReflectionRoot(method, reason); } + public static bool TryRootField(IRootingServiceProvider rootProvider, FieldDesc field, string reason) + { + try + { + RootField(rootProvider, field, reason); + return true; + } + catch (TypeSystemException) + { + return false; + } + } + + public static void RootField(IRootingServiceProvider rootProvider, FieldDesc field, string reason) + { + // Make sure we're not putting something into the graph that will crash later. + if (field.IsLiteral) + { + // Nothing to check + } + else if (field.IsStatic) + { + field.OwningType.ComputeStaticFieldLayout(StaticLayoutKind.StaticRegionSizes); + } + else + { + field.OwningType.ComputeInstanceLayout(InstanceLayoutKind.TypeOnly); + } + + rootProvider.AddReflectionRoot(field, reason); + } + public static bool TryGetDependenciesForReflectedMethod(ref DependencyList dependencies, NodeFactory factory, MethodDesc method, string reason) { MethodDesc typicalMethod = method.GetTypicalMethodDefinition(); @@ -138,7 +175,7 @@ public static bool TryGetDependenciesForReflectedMethod(ref DependencyList depen if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true)) { TypeDesc owningType = method.OwningType.GetTypeDefinition(); - Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: false); + Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: !method.HasInstantiation); if (inst.IsNull) { return false; @@ -180,6 +217,22 @@ public static bool TryGetDependenciesForReflectedMethod(ref DependencyList depen public static bool TryGetDependenciesForReflectedField(ref DependencyList dependencies, NodeFactory factory, FieldDesc field, string reason) { + FieldDesc typicalField = field.GetTypicalFieldDefinition(); + if (factory.MetadataManager.IsReflectionBlocked(typicalField)) + { + return false; + } + + dependencies ??= new DependencyList(); + + // If this is a field on generic type, make sure we at minimum have the metadata + // for it. This hedges against the risk that we fail to figure out an instantiated base + // for it below. + if (typicalField.OwningType.HasInstantiation) + { + dependencies.Add(factory.ReflectableField(typicalField), reason); + } + // If there's any genericness involved, try to create a fitting instantiation that would be usable at runtime. // This is not a complete solution to the problem. // If we ever decide that MakeGenericType/MakeGenericMethod should simply be considered unsafe, this code can be deleted @@ -198,45 +251,7 @@ public static bool TryGetDependenciesForReflectedField(ref DependencyList depend ((MetadataType)owningType).MakeInstantiatedType(inst)); } - if (factory.MetadataManager.IsReflectionBlocked(field)) - { - return false; - } - - if (!TryGetDependenciesForReflectedType(ref dependencies, factory, field.OwningType, reason)) - { - return false; - } - - // Currently generating the base of the type is enough to make the field reflectable. - - if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) - { - return true; - } - - if (field.IsStatic && !field.IsLiteral && !field.HasRva) - { - bool cctorContextAdded = false; - if (field.IsThreadStatic) - { - dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)field.OwningType), reason); - } - else if (field.HasGCStaticBase) - { - dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)field.OwningType), reason); - } - else - { - dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType), reason); - cctorContextAdded = true; - } - - if (!cctorContextAdded && factory.PreinitializationManager.HasLazyStaticConstructor(field.OwningType)) - { - dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType), reason); - } - } + dependencies.Add(factory.ReflectableField(field), reason); return true; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingServiceProvider.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingServiceProvider.cs index ce5dd8f931f91..31419393a1d84 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingServiceProvider.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingServiceProvider.cs @@ -46,6 +46,12 @@ public void AddReflectionRoot(MethodDesc method, string reason) _rootAdder(_factory.ReflectableMethod(method), reason); } + public void AddReflectionRoot(FieldDesc field, string reason) + { + if (!_factory.MetadataManager.IsReflectionBlocked(field)) + _rootAdder(_factory.ReflectableField(field), reason); + } + public void RootThreadStaticBaseForType(TypeDesc type, string reason) { Debug.Assert(!type.IsGenericDefinition); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index c5b5a458afbd3..77af00708d864 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -40,7 +40,6 @@ public sealed class UsageBasedMetadataManager : GeneratingMetadataManager private readonly CompilationModuleGroup _compilationModuleGroup; internal readonly UsageBasedMetadataGenerationOptions _generationOptions; - private readonly bool _hasPreciseFieldUsageInformation; private readonly FeatureSwitchHashtable _featureSwitchHashtable; @@ -48,6 +47,7 @@ public sealed class UsageBasedMetadataManager : GeneratingMetadataManager private readonly List _fieldsWithMetadata = new List(); private readonly List _methodsWithMetadata = new List(); private readonly List _typesWithMetadata = new List(); + private readonly List _fieldsWithRuntimeMapping = new List(); private readonly List _customAttributesWithMetadata = new List(); private readonly HashSet _rootEntireAssembliesExaminedModules = new HashSet(); @@ -75,8 +75,6 @@ public UsageBasedMetadataManager( IEnumerable trimmedAssemblies) : base(typeSystemContext, blockingPolicy, resourceBlockingPolicy, logFile, stackTracePolicy, invokeThunkGenerationPolicy) { - // We use this to mark places that would behave differently if we tracked exact fields used. - _hasPreciseFieldUsageInformation = false; _compilationModuleGroup = group; _generationOptions = generationOptions; @@ -122,6 +120,22 @@ protected override void Graph_NewMarkedNode(DependencyNodeCore obj) { _customAttributesWithMetadata.Add(customAttributeMetadataNode.CustomAttribute); } + + var reflectableFieldNode = obj as ReflectableFieldNode; + if (reflectableFieldNode != null) + { + FieldDesc field = reflectableFieldNode.Field; + TypeDesc fieldOwningType = field.OwningType; + + // Filter out to those that make sense to have in the mapping tables + if (!fieldOwningType.IsGenericDefinition + && !field.IsLiteral + && (!fieldOwningType.IsCanonicalSubtype(CanonicalFormKind.Specific) || !field.IsStatic)) + { + Debug.Assert((GetMetadataCategory(field) & MetadataCategory.RuntimeMapping) != 0); + _fieldsWithRuntimeMapping.Add(field); + } + } } protected override MetadataCategory GetMetadataCategory(FieldDesc field) @@ -173,7 +187,7 @@ protected override MetadataCategory GetMetadataCategory(TypeDesc type) return category; } - protected override bool AllMethodsCanBeReflectable => (_generationOptions & UsageBasedMetadataGenerationOptions.ReflectedMembersOnly) == 0; + protected override bool AllMethodsCanBeReflectable => (_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0; protected override void ComputeMetadata(NodeFactory factory, out byte[] metadataBlob, @@ -192,26 +206,16 @@ protected override void GetMetadataDependenciesDueToReflectability(ref Dependenc dependencies.Add(factory.MethodMetadata(method.GetTypicalMethodDefinition()), "Reflectable method"); } + protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, FieldDesc field) + { + dependencies = dependencies ?? new DependencyList(); + dependencies.Add(factory.FieldMetadata(field.GetTypicalFieldDefinition()), "Reflectable field"); + } + protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) { TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, type, "Reflectable type"); - // If we don't have precise field usage information, apply policy that all fields that - // are eligible to have metadata get metadata. - if (!_hasPreciseFieldUsageInformation) - { - TypeDesc typeDefinition = type.GetTypeDefinition(); - - foreach (FieldDesc field in typeDefinition.GetFields()) - { - if ((GetMetadataCategory(field) & MetadataCategory.Description) != 0) - { - dependencies = dependencies ?? new DependencyList(); - dependencies.Add(factory.FieldMetadata(field), "Field of a reflectable type"); - } - } - } - MetadataType mdType = type as MetadataType; // If anonymous type heuristic is turned on and this is an anonymous type, make sure we have @@ -338,48 +342,19 @@ private static bool IsTrimmableAssembly(ModuleDesc assembly) return false; } - protected override void GetRuntimeMappingDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + public override bool HasConditionalDependenciesDueToEETypePresence(TypeDesc type) { - // If we precisely track field usage, we don't need the logic below. - if (_hasPreciseFieldUsageInformation) - return; - - const string reason = "Reflection"; - - // This logic is applying policy: if a type is reflectable (has a runtime mapping), all of it's fields - // are reflectable (with a runtime mapping) as well. - // This is potentially overly broad (we don't know if any of the fields will actually be eligile - // for metadata - e.g. they could all be reflection blocked). This is fine since lack of - // precise field usage information is already not ideal from a size on disk perspective. - // The more precise way to do this would be to go over each field, check that it's eligible for RuntimeMapping - // according to the policy (e.g. it's not blocked), and only then root the base of the field. - if (type is MetadataType metadataType && !type.IsGenericDefinition) - { - Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any)); + // Note: these are duplicated with the checks in GetConditionalDependenciesDueToEETypePresence - if (metadataType.GCStaticFieldSize.AsInt > 0) - { - dependencies.Add(factory.TypeGCStaticsSymbol(metadataType), reason); - } - - if (metadataType.NonGCStaticFieldSize.AsInt > 0 || factory.PreinitializationManager.HasLazyStaticConstructor(metadataType)) - { - dependencies.Add(factory.TypeNonGCStaticsSymbol(metadataType), reason); - } - - if (metadataType.ThreadGcStaticFieldSize.AsInt > 0) - { - dependencies.Add(factory.TypeThreadStaticIndex(metadataType), reason); - } + // If there's dataflow annotations on the type, we have conditional dependencies + if (type.IsDefType && !type.IsInterface && FlowAnnotations.GetTypeAnnotation(type) != default) + return true; - Debug.Assert(metadataType.ThreadNonGcStaticFieldSize.AsInt == 0); - } - } + // If we need to ensure fields are consistently reflectable on various generic instances + if (type.HasInstantiation && !type.IsGenericDefinition && !IsReflectionBlocked(type)) + return true; - public override bool HasConditionalDependenciesDueToEETypePresence(TypeDesc type) - { - // Note: duplicated with the check in GetConditionalDependenciesDueToEETypePresence - return type.IsDefType && !type.IsInterface && FlowAnnotations.GetTypeAnnotation(type) != default; + return false; } public override void GetConditionalDependenciesDueToEETypePresence(ref CombinedDependencyList dependencies, NodeFactory factory, TypeDesc type) @@ -435,16 +410,34 @@ public override void GetConditionalDependenciesDueToEETypePresence(ref CombinedD // of the bases/interfaces are annotated. // ObjectGetTypeFlowDependencies don't need to be conditional in that case. They'll be added as needed. } + + // Ensure fields can be consistently reflection set & get. + if (type.HasInstantiation && !type.IsTypeDefinition && !IsReflectionBlocked(type)) + { + foreach (FieldDesc field in type.GetFields()) + { + // Tiny optimization: no get/set for literal fields since they only exist in metadata + if (field.IsLiteral) + continue; + + if (IsReflectionBlocked(field)) + continue; + + dependencies ??= new CombinedDependencyList(); + dependencies.Add(new DependencyNodeCore.CombinedDependencyListEntry( + factory.ReflectableField(field), + factory.ReflectableField(field.GetTypicalFieldDefinition()), + "GetType called on the interface")); + } + } } public override void GetDependenciesDueToLdToken(ref DependencyList dependencies, NodeFactory factory, FieldDesc field) { - // In order for the RuntimeFieldHandle data structure to be usable at runtime, ensure the field - // is generating metadata. - if ((GetMetadataCategory(field) & MetadataCategory.Description) == MetadataCategory.Description) + if (!IsReflectionBlocked(field)) { dependencies = dependencies ?? new DependencyList(); - dependencies.Add(factory.FieldMetadata(field.GetTypicalFieldDefinition()), "LDTOKEN field"); + dependencies.Add(factory.ReflectableField(field), "LDTOKEN field"); } } @@ -534,18 +527,38 @@ protected override void GetDependenciesDueToMethodCodePresenceInternal(ref Depen } // Presence of code might trigger the reflectability dependencies. - if ((_generationOptions & UsageBasedMetadataGenerationOptions.ReflectedMembersOnly) == 0) + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0) { GetDependenciesDueToReflectability(ref dependencies, factory, method); } } + public override void GetConditionalDependenciesDueToMethodGenericDictionary(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method) + { + Debug.Assert(!method.IsSharedByGenericInstantiations && method.HasInstantiation && method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method); + + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) == 0 + && !IsReflectionBlocked(method)) + { + // Ensure that if SomeMethod is considered reflectable, SomeMethod is also reflectable. + // We only need this because there's a file format limitation in the reflection mapping tables that + // requires generic methods to be concrete (i.e. SomeMethod<__Canon> can never be in the mapping table). + // If we ever lift this limitation, this code can be deleted: the reflectability is going to be covered + // by GetConditionalDependenciesDueToMethodCodePresence below (we get that callback for SomeMethod<__Canon>). + MethodDesc typicalMethod = method.GetTypicalMethodDefinition(); + + dependencies ??= new CombinedDependencyList(); + dependencies.Add(new DependencyNodeCore.CombinedDependencyListEntry( + factory.ReflectableMethod(method), factory.ReflectableMethod(typicalMethod), "Reflectability of methods is same across genericness")); + } + } + public override void GetConditionalDependenciesDueToMethodCodePresence(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method) { MethodDesc typicalMethod = method.GetTypicalMethodDefinition(); // Ensure methods with genericness have the same reflectability by injecting a conditional dependency. - if ((_generationOptions & UsageBasedMetadataGenerationOptions.ReflectedMembersOnly) != 0 + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) == 0 && method != typicalMethod) { dependencies ??= new CombinedDependencyList(); @@ -556,7 +569,7 @@ public override void GetConditionalDependenciesDueToMethodCodePresence(ref Combi public override void GetDependenciesDueToVirtualMethodReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { - if ((_generationOptions & UsageBasedMetadataGenerationOptions.ReflectedMembersOnly) == 0) + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0) { // If we have a use of an abstract method, GetDependenciesDueToReflectability is not going to see the method // as being used since there's no body. We inject a dependency on a new node that serves as a logical method body @@ -571,26 +584,7 @@ public override void GetDependenciesDueToVirtualMethodReflectability(ref Depende protected override IEnumerable GetFieldsWithRuntimeMapping() { - if (_hasPreciseFieldUsageInformation) - { - // TODO - } - else - { - // This applies a policy that fields inherit runtime mapping from their owning type, - // unless they are blocked. - foreach (var type in GetTypesWithRuntimeMapping()) - { - if (type.IsGenericDefinition) - continue; - - foreach (var field in type.GetFields()) - { - if ((GetMetadataCategory(field) & MetadataCategory.RuntimeMapping) != 0) - yield return field; - } - } - } + return _fieldsWithRuntimeMapping; } public override IEnumerable GetCompilationModulesWithMetadata() @@ -625,6 +619,60 @@ public override void GetDependenciesDueToAccess(ref DependencyList dependencies, dependencies = dependencies ?? new DependencyList(); dependencies.Add(factory.DataflowAnalyzedMethod(methodIL.GetMethodILDefinition()), "Access to interesting field"); } + + string reason = "Use of a field"; + + bool generatesMetadata = false; + if (!IsReflectionBlocked(writtenField)) + { + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0) + { + // If access to the field should trigger metadata generation, we should generate the field + generatesMetadata = true; + } + else + { + // There's an invalid suppression in the CoreLib that assumes used fields on attributes will be kept. + // It's used in the reflection-based implementation of Attribute.Equals and Attribute.GetHashCode. + // .NET Native used to have a non-reflection based implementation of Equals/GetHashCode to get around + // this problem. We could explore that as well, but for now, emulate the fact that accessed fields + // on custom attributes will be visible in reflection metadata. + MetadataType currentType = (MetadataType)writtenField.OwningType.BaseType; + while (currentType != null) + { + if (currentType.Module == factory.TypeSystemContext.SystemModule + && currentType.Name == "Attribute" && currentType.Namespace == "System") + { + generatesMetadata = true; + reason = "Field of an attribute"; + break; + } + + currentType = currentType.MetadataBaseType; + } + } + } + + if (generatesMetadata) + { + FieldDesc fieldToReport = writtenField; + + // The field could be on something odd like Foo<__Canon, object>. Normalize to Foo<__Canon, __Canon>. + TypeDesc fieldOwningType = writtenField.OwningType; + if (fieldOwningType.IsCanonicalSubtype(CanonicalFormKind.Specific)) + { + TypeDesc fieldOwningTypeNormalized = fieldOwningType.NormalizeInstantiation(); + if (fieldOwningType != fieldOwningTypeNormalized) + { + fieldToReport = factory.TypeSystemContext.GetFieldForInstantiatedType( + writtenField.GetTypicalFieldDefinition(), + (InstantiatedType)fieldOwningTypeNormalized); + } + } + + dependencies = dependencies ?? new DependencyList(); + dependencies.Add(factory.ReflectableField(fieldToReport), reason); + } } public override void GetDependenciesDueToAccess(ref DependencyList dependencies, NodeFactory factory, MethodIL methodIL, MethodDesc calledMethod) @@ -655,13 +703,21 @@ private void GetFlowDependenciesForInstantiation(ref DependencyList dependencies var genericParameter = (GenericParameterDesc)typicalInstantiation[i]; if (FlowAnnotations.GetGenericParameterAnnotation(genericParameter) != default) { - var deps = ILCompiler.Dataflow.ReflectionMethodBodyScanner.ProcessGenericArgumentDataFlow(factory, FlowAnnotations, Logger, genericParameter, instantiation[i], source); - if (deps.Count > 0) + try + { + var deps = ILCompiler.Dataflow.ReflectionMethodBodyScanner.ProcessGenericArgumentDataFlow(factory, FlowAnnotations, Logger, genericParameter, instantiation[i], source); + if (deps.Count > 0) + { + if (dependencies == null) + dependencies = deps; + else + dependencies.AddRange(deps); + } + } + catch (TypeSystemException) { - if (dependencies == null) - dependencies = deps; - else - dependencies.AddRange(deps); + // Wasn't able to do dataflow because of missing references or something like that. + // This likely won't compile either, so we don't care about missing dependencies. } } } @@ -685,6 +741,12 @@ public override void GetDependenciesForGenericDictionary(ref DependencyList depe GetFlowDependenciesForInstantiation(ref dependencies, factory, owningType.Instantiation, owningType.GetTypeDefinition().Instantiation, method); } } + + // Presence of code might trigger the reflectability dependencies. + if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0) + { + GetDependenciesDueToReflectability(ref dependencies, factory, method); + } } public override void GetDependenciesForGenericDictionary(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) @@ -795,41 +857,16 @@ public MetadataManager ToAnalysisBasedMetadataManager() reflectableFields[fieldWithMetadata] = MetadataCategory.Description; } - if (_hasPreciseFieldUsageInformation) + foreach (var fieldWithRuntimeMapping in _fieldsWithRuntimeMapping) { - // TODO - } - else - { - // If we don't have precise field usage information we apply a policy that - // says the fields inherit the setting from the type, potentially restricted by blocking. - // (I.e. if a type has RuntimeMapping metadata, the field has RuntimeMapping too, unless blocked.) - foreach (var reflectableType in reflectableTypes.ToEnumerable()) - { - if (reflectableType.Entity.IsGenericDefinition) - continue; - - if (reflectableType.Entity.IsCanonicalSubtype(CanonicalFormKind.Specific)) - continue; - - if ((reflectableType.Category & MetadataCategory.RuntimeMapping) == 0) - continue; + reflectableFields[fieldWithRuntimeMapping] |= MetadataCategory.RuntimeMapping; - foreach (var field in reflectableType.Entity.GetFields()) - { - if (!IsReflectionBlocked(field)) - { - reflectableFields[field] |= MetadataCategory.RuntimeMapping; - - // Also set the description bit if the definition is getting metadata. - FieldDesc typicalField = field.GetTypicalFieldDefinition(); - if (field != typicalField && - (reflectableFields[typicalField] & MetadataCategory.Description) != 0) - { - reflectableFields[field] |= MetadataCategory.Description; - } - } - } + // Also set the description bit if the definition is getting metadata. + FieldDesc typicalField = fieldWithRuntimeMapping.GetTypicalFieldDefinition(); + if (fieldWithRuntimeMapping != typicalField && + (reflectableFields[typicalField] & MetadataCategory.Description) != 0) + { + reflectableFields[fieldWithRuntimeMapping] |= MetadataCategory.Description; } } @@ -1068,9 +1105,9 @@ public enum UsageBasedMetadataGenerationOptions ReflectionILScanning = 4, /// - /// Only members that were seen as reflected on will be reflectable. + /// Consider all native artifacts (native method bodies, etc) visible from reflection. /// - ReflectedMembersOnly = 8, + CreateReflectableArtifacts = 8, /// /// Fully root used assemblies that are not marked IsTrimmable in metadata. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 20246847b661c..0f4dded3fe585 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -264,6 +264,8 @@ private void ImportCall(ILOpcode opcode, int token) var method = (MethodDesc)_canonMethodIL.GetObject(token); _compilation.TypeSystemContext.EnsureLoadableMethod(method); + if ((method.Signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == MethodSignatureFlags.CallingConventionVarargs) + ThrowHelper.ThrowBadImageFormatException(); _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _dependencies, _compilation.NodeFactory, _canonMethodIL, method); @@ -975,8 +977,9 @@ private void ImportReadOnlyPrefix() private void ImportFieldAccess(int token, bool isStatic, string reason) { var field = (FieldDesc)_methodIL.GetObject(token); + var canonField = (FieldDesc)_canonMethodIL.GetObject(token); - _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _dependencies, _compilation.NodeFactory, _canonMethodIL, field); + _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _dependencies, _compilation.NodeFactory, _canonMethodIL, canonField); // Covers both ldsfld/ldsflda and ldfld/ldflda with a static field if (isStatic || field.IsStatic) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 6f19f9f7acc73..12fadf2a915f3 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -300,6 +300,8 @@ + + @@ -351,6 +353,7 @@ + diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs index be0d8af909f72..62bdb023525e6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs @@ -218,7 +218,12 @@ private void WritePDBDataHelper(string dllPath, IEnumerable methods) const int capacity = 1024; var pdbFilePathBuilder = new char[capacity]; _ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(capacity - 1) /* remove 1 byte for null */); - _pdbFilePath = pdbFilePathBuilder.ToString(); + int length = 0; + while (length < pdbFilePathBuilder.Length && pdbFilePathBuilder[length] != '\0') + { + length++; + } + _pdbFilePath = new string(pdbFilePathBuilder, 0, length); } _ngenWriter.OpenModW(originalDllPath, Path.GetFileName(originalDllPath), out _pdbMod); diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs index 8a1166f43a39b..619f319888fc9 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs @@ -21,6 +21,7 @@ private SymNgenWriterWrapper(IntPtr writer2Inst) { var iid = ISymNGenWriter2.IID; int hr = Marshal.QueryInterface(ptr, ref iid, out IntPtr ngenWriterInst); + Marshal.Release(ptr); if (hr != 0) { return null; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 550b4e451adc0..44925d84cfe21 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -663,7 +663,7 @@ public void AttachToDependencyGraph(DependencyAnalyzerBase graph) if (inputModule == TypeSystemContext.SystemModule) { AttributePresenceFilterNode attributePresenceTable = new AttributePresenceFilterNode(inputModule); - Header.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, attributePresenceTable, attributePresenceTable); + tableHeader.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, attributePresenceTable, attributePresenceTable); } } 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 2e7452815e652..6e62f81bdbf34 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -361,8 +361,9 @@ unsafe partial class CorInfoImpl private MethodWithGCInfo _methodCodeNode; private OffsetMapping[] _debugLocInfos; private NativeVarInfo[] _debugVarInfos; - private ArrayBuilder _inlinedMethods; + private HashSet _inlinedMethods; private UnboxingMethodDescFactory _unboxingThunkFactory = new UnboxingMethodDescFactory(); + private List _precodeFixups; public CorInfoImpl(ReadyToRunCodegenCompilation compilation) : this() @@ -370,6 +371,12 @@ public CorInfoImpl(ReadyToRunCodegenCompilation compilation) _compilation = compilation; } + private void AddPrecodeFixup(ISymbolNode node) + { + _precodeFixups = _precodeFixups ?? new List(); + _precodeFixups.Add(node); + } + private static mdToken FindGenericMethodArgTypeSpec(EcmaModule module) { // Find the TypeSpec for "!!0" @@ -1327,7 +1334,7 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset)) { // ENCODE_CHECK_FIELD_OFFSET - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } } else @@ -1381,7 +1388,7 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset)) { // ENCODE_CHECK_FIELD_OFFSET - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } pResult->fieldLookup = CreateConstLookupToSymbol( @@ -1843,7 +1850,7 @@ private void classMustBeLoadedBeforeCodeIsRun(TypeDesc type) if (!type.IsPrimitive) { ISymbolNode node = _compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeHandle, type); - _methodCodeNode.Fixups.Add(node); + AddPrecodeFixup(node); } } @@ -2365,7 +2372,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, if (pResult->offset > FieldFixupSignature.MaxCheckableOffset) throw new RequiresRuntimeJitException(callerMethod.ToString() + " -> " + field.ToString()); - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); // No-op other than generating the check field offset fixup } else @@ -2383,7 +2390,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset)) { // ENCODE_CHECK_FIELD_OFFSET - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } // ENCODE_NONE } @@ -2392,7 +2399,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset)) { // ENCODE_CHECK_FIELD_OFFSET - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } // ENCODE_NONE } @@ -2403,7 +2410,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset)) { // ENCODE_CHECK_FIELD_OFFSET - _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + AddPrecodeFixup(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); } // ENCODE_FIELD_BASE_OFFSET @@ -2636,14 +2643,56 @@ private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) _ehClauses[EHnumber] = clause; } + private readonly Stack> _stashedPrecodeFixups = new Stack>(); + private readonly Stack> _stashedInlinedMethods = new Stack>(); + + private void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + _stashedPrecodeFixups.Push(_precodeFixups); + _precodeFixups = null; + _stashedInlinedMethods.Push(_inlinedMethods); + _inlinedMethods = null; + } + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) { if (inlineResult == CorInfoInline.INLINE_PASS) { // We deliberately ignore inlinerHnd because we have no interest to track intermediate links now. MethodDesc inlinee = HandleToObject(inlineeHnd); + + // If during inlining we found Precode fixups, then only if the inline was successful, add them to the set of + // fixups that will be used for the entire method + List previouslyStashedFixups = _stashedPrecodeFixups.Pop(); + + if (_precodeFixups != null) + { + previouslyStashedFixups = previouslyStashedFixups ?? new List(); + previouslyStashedFixups.AddRange(_precodeFixups); + } + _precodeFixups = previouslyStashedFixups; + + // If during inlining we found new inlinees, then if the inline was successful, add them to the set of fixups + // for the entire method. + HashSet previouslyStashedInlinees = _stashedInlinedMethods.Pop(); + if (_inlinedMethods != null) + { + previouslyStashedInlinees = previouslyStashedInlinees ?? new HashSet(); + foreach (var inlineeInHashSet in _inlinedMethods) + previouslyStashedInlinees.Add(inlineeInHashSet); + } + _inlinedMethods = previouslyStashedInlinees; + + // Then add the fact we inlined this method. + _inlinedMethods = _inlinedMethods ?? new HashSet(); _inlinedMethods.Add(inlinee); } + else + { + // If we didn't succeed on the inline, just pop back to the state before inlining + _precodeFixups = _stashedPrecodeFixups.Pop(); + _inlinedMethods = _stashedInlinedMethods.Pop(); + } } private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) 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 f6eeb8343c0b1..c2845403c2a55 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -1854,19 +1854,10 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN private void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) { - // TODO: fully implement GS cookies - - if (pCookieVal != null) + if (ppCookieVal != null) { - if (PointerSize == 4) - { - *pCookieVal = (IntPtr)0x3F796857; - } - else - { - *pCookieVal = unchecked((IntPtr)0x216D6F6D202C6948); - } - *ppCookieVal = null; + *ppCookieVal = (IntPtr*)ObjectToHandle(_compilation.NodeFactory.ExternSymbol("__security_cookie")); + *pCookieVal = IntPtr.Zero; } else { @@ -1979,6 +1970,10 @@ private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) _ehClauses[EHnumber] = clause; } + private void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + } + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) { } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/Signature.il b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/Signature.il index 32e307b7036c8..5a528fda34d77 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/Signature.il +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/Signature.il @@ -39,6 +39,8 @@ { ret } + + .field private bool modreq([CoreTestAssembly]System.Void) fieldWithModOpt } .class private auto ansi beforefieldinit Atom diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/SignatureTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/SignatureTests.cs index ac8d2bc168372..23e1a9f58cfe2 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/SignatureTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/SignatureTests.cs @@ -197,6 +197,35 @@ public void TestSerializedSignatureWithReferenceToMDIntArray() Assert.Equal(typeInLookupContext, int32ArrayFromLookup); } + [Fact] + public void TestSerializedSignatureWithReferenceToFieldWithModOpt() + { + + MetadataType modOptTester = _testModule.GetType("", "ModOptTester"); + FieldDesc fieldWithModOpt = modOptTester.GetFields().Single(m => string.Equals(m.Name, "fieldWithModOpt")); + + // Create assembly with reference to interesting method + TypeSystemMetadataEmitter metadataEmitter = new TypeSystemMetadataEmitter(new System.Reflection.AssemblyName("Lookup"), _context); + var token = metadataEmitter.GetFieldRef(fieldWithModOpt); + MemoryStream peStream = new MemoryStream(); + metadataEmitter.SerializeToStream(peStream); + + peStream.Seek(0, SeekOrigin.Begin); + + // Create new TypeSystemContext with just created assembly inside + var lookupContext = new TestTypeSystemContext(TargetArchitecture.X64); + var systemModule = lookupContext.CreateModuleForSimpleName("CoreTestAssembly"); + lookupContext.SetSystemModule(systemModule); + + lookupContext.CreateModuleForSimpleName("Lookup", peStream); + + // Use generated assembly to trigger a load through the token created above and verify that it loads correctly + var ilLookupModule = (EcmaModule)lookupContext.GetModuleForSimpleName("Lookup"); + FieldDesc fieldFound = ilLookupModule.GetField(token); + + Assert.Equal("fieldWithModOpt", fieldFound.Name); + } + [Fact] public void TestMDArrayFunctionReading() { diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs index 925fd5c9a90d8..eb3643851fd50 100644 --- a/src/coreclr/tools/aot/ILCompiler/Program.cs +++ b/src/coreclr/tools/aot/ILCompiler/Program.cs @@ -53,9 +53,8 @@ internal class Program private string _mapFileName; private string _metadataLogFileName; private bool _noMetadataBlocking; - private bool _disableReflection; + private string _reflectionData; private bool _completeTypesMetadata; - private bool _reflectedOnly; private bool _scanReflection; private bool _methodBodyFolding; private int _parallelism = Environment.ProcessorCount; @@ -159,6 +158,8 @@ private void InitializeDefaultOptions() private ArgumentSyntax ParseCommandLine(string[] args) { + var validReflectionDataOptions = new string[] { "all", "none" }; + IReadOnlyList inputFiles = Array.Empty(); IReadOnlyList referenceFiles = Array.Empty(); @@ -201,9 +202,8 @@ private ArgumentSyntax ParseCommandLine(string[] args) syntax.DefineOption("map", ref _mapFileName, "Generate a map file"); syntax.DefineOption("metadatalog", ref _metadataLogFileName, "Generate a metadata log file"); syntax.DefineOption("nometadatablocking", ref _noMetadataBlocking, "Ignore metadata blocking for internal implementation details"); - syntax.DefineOption("disablereflection", ref _disableReflection, "Disable generation of reflection metadata"); syntax.DefineOption("completetypemetadata", ref _completeTypesMetadata, "Generate complete metadata for types"); - syntax.DefineOption("reflectedonly", ref _reflectedOnly, "Generate metadata only for reflected members"); + syntax.DefineOption("reflectiondata", ref _reflectionData, $"Reflection data to generate (one of: {string.Join(", ", validReflectionDataOptions)})"); syntax.DefineOption("scanreflection", ref _scanReflection, "Scan IL for reflection patterns"); syntax.DefineOption("scan", ref _useScanner, "Use IL scanner to generate optimized code (implied by -O)"); syntax.DefineOption("noscan", ref _noScanner, "Do not use IL scanner to generate optimized code"); @@ -342,6 +342,11 @@ private ArgumentSyntax ParseCommandLine(string[] args) Helpers.MakeReproPackage(_makeReproPath, _outputFilePath, args, argSyntax, new[] { "-r", "-m", "--rdxml", "--directpinvokelist" }); } + if (_reflectionData != null && Array.IndexOf(validReflectionDataOptions, _reflectionData) < 0) + { + Console.WriteLine($"Warning: option '{_reflectionData}' not recognized"); + } + return argSyntax; } @@ -527,7 +532,7 @@ private int Run(string[] args) InstructionSetSupportBuilder.GetNonSpecifiableInstructionSetsForArch(_targetArchitecture), _targetArchitecture); - bool supportsReflection = !_disableReflection && _systemModuleName == DefaultSystemModule; + bool supportsReflection = _reflectionData != "none" && _systemModuleName == DefaultSystemModule; // // Initialize type system context @@ -758,8 +763,8 @@ static string ILLinkify(string rootedAssembly) metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.CompleteTypesOnly; if (_scanReflection) metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.ReflectionILScanning; - if (_reflectedOnly) - metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.ReflectedMembersOnly; + if (_reflectionData == "all") + metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts; if (_rootDefaultAssemblies) metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.RootDefaultAssemblies; } diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/AddedPseudoAttributeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/AddedPseudoAttributeAttribute.cs new file mode 100644 index 0000000000000..92c4b044ba93f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/AddedPseudoAttributeAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event, AllowMultiple = true, Inherited = false)] + public class AddedPseudoAttributeAttribute : BaseExpectedLinkedBehaviorAttribute + { + public AddedPseudoAttributeAttribute (uint value) + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs new file mode 100644 index 0000000000000..9a963f6105571 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Base attribute for attributes that mark up the expected behavior of the linker on a member + /// + [Conditional ("INCLUDE_EXPECTATIONS")] + public abstract class BaseExpectedLinkedBehaviorAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseInAssemblyAttribute.cs new file mode 100644 index 0000000000000..1d8ed24b3645c --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseInAssemblyAttribute.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + public abstract class BaseInAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseMemberAssertionAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseMemberAssertionAttribute.cs new file mode 100644 index 0000000000000..5afd16cfd6d9e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseMemberAssertionAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// A base class for attributes that make assertions about a particular member. + // The test infrastructure is expected to check the assertion on the member to which + // the attribute is applied. + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Delegate, AllowMultiple = true)] + public abstract class BaseMemberAssertionAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/CreatedMemberAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/CreatedMemberAttribute.cs new file mode 100644 index 0000000000000..9fdbb1938776e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/CreatedMemberAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)] + public sealed class CreatedMemberAttribute : BaseExpectedLinkedBehaviorAttribute + { + + public CreatedMemberAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DependencyRecordedAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DependencyRecordedAttribute.cs new file mode 100644 index 0000000000000..7220234672566 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DependencyRecordedAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class DependencyRecordedAttribute : BaseExpectedLinkedBehaviorAttribute + { + public DependencyRecordedAttribute (string source, string target, string marked = null) + { + if (string.IsNullOrEmpty (source)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (source)); + + if (string.IsNullOrEmpty (target)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (target)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DisplayNameAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DisplayNameAttribute.cs new file mode 100644 index 0000000000000..3e369a539e630 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/DisplayNameAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + public class DisplayNameAttribute : BaseMemberAssertionAttribute + { + public DisplayNameAttribute (string expectedDisplayName) + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/EnableLoggerAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/EnableLoggerAttribute.cs new file mode 100644 index 0000000000000..436281610fbeb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/EnableLoggerAttribute.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + public abstract class EnableLoggerAttribute : BaseExpectedLinkedBehaviorAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectBodyModifiedAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectBodyModifiedAttribute.cs new file mode 100644 index 0000000000000..dbe07219cf015 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectBodyModifiedAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public class ExpectBodyModifiedAttribute : BaseInAssemblyAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExactlyResolvedDocumentationSignatureAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExactlyResolvedDocumentationSignatureAttribute.cs new file mode 100644 index 0000000000000..b618ed7a35486 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExactlyResolvedDocumentationSignatureAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// Asserts that the given documentation signature string resolves to the + // member with this attribute, and only that member. + public class ExpectExactlyResolvedDocumentationSignatureAttribute : BaseMemberAssertionAttribute + { + public ExpectExactlyResolvedDocumentationSignatureAttribute (string input) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExceptionHandlersModifiedAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExceptionHandlersModifiedAttribute.cs new file mode 100644 index 0000000000000..a76e4b6489777 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectExceptionHandlersModifiedAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public class ExpectExceptionHandlersModifiedAttribute : BaseInAssemblyAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectGeneratedDocumentationSignatureAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectGeneratedDocumentationSignatureAttribute.cs new file mode 100644 index 0000000000000..c25b2ff3d0262 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectGeneratedDocumentationSignatureAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// Asserts that the member to which this attribute is applied has the given + /// documentation signature. + public class ExpectGeneratedDocumentationSignatureAttribute : BaseMemberAssertionAttribute + { + public ExpectGeneratedDocumentationSignatureAttribute (string expected) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectLocalsModifiedAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectLocalsModifiedAttribute.cs new file mode 100644 index 0000000000000..56a30bd52d20c --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectLocalsModifiedAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public class ExpectLocalsModifiedAttribute : BaseInAssemblyAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectResolvedDocumentationSignatureAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectResolvedDocumentationSignatureAttribute.cs new file mode 100644 index 0000000000000..5a3c16fe9bcc2 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectResolvedDocumentationSignatureAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// Asserts that the given documentation signature string resolves to the + // member with this attribute. + public class ExpectResolvedDocumentationSignatureAttribute : BaseMemberAssertionAttribute + { + public ExpectResolvedDocumentationSignatureAttribute (string input) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectUnresolvedDocumentationSignatureAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectUnresolvedDocumentationSignatureAttribute.cs new file mode 100644 index 0000000000000..aea9068451bcc --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectUnresolvedDocumentationSignatureAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// Asserts that the given documentation signature string does not resolve + /// to the member with this attribute. + public class ExpectUnresolvedDocumentationSignatureAttribute : BaseMemberAssertionAttribute + { + public ExpectUnresolvedDocumentationSignatureAttribute (string expected) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceAttribute.cs new file mode 100644 index 0000000000000..35ead6966a4f6 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public class ExpectedInstructionSequenceAttribute : BaseInAssemblyAttribute + { + public ExpectedInstructionSequenceAttribute (string[] opCodes) + { + if (opCodes == null) + throw new ArgumentNullException (nameof (opCodes)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceOnMemberInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceOnMemberInAssemblyAttribute.cs new file mode 100644 index 0000000000000..899b979c5211e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedInstructionSequenceOnMemberInAssemblyAttribute.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public class ExpectedInstructionSequenceOnMemberInAssemblyAttribute : BaseInAssemblyAttribute + { + public ExpectedInstructionSequenceOnMemberInAssemblyAttribute (string assemblyFileName, Type type, string memberName, string[] opCodes) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (memberName)) + throw new ArgumentNullException (nameof (memberName)); + if (opCodes == null) + throw new ArgumentNullException (nameof (opCodes)); + } + + public ExpectedInstructionSequenceOnMemberInAssemblyAttribute (string assemblyFileName, string typeName, string memberName, string[] opCodes) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentNullException (nameof (typeName)); + if (string.IsNullOrEmpty (memberName)) + throw new ArgumentNullException (nameof (memberName)); + if (opCodes == null) + throw new ArgumentNullException (nameof (opCodes)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedLocalsSequenceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedLocalsSequenceAttribute.cs new file mode 100644 index 0000000000000..fdd3441b71f44 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedLocalsSequenceAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public class ExpectedLocalsSequenceAttribute : BaseInAssemblyAttribute + { + public ExpectedLocalsSequenceAttribute (string[] types) + { + if (types == null) + throw new ArgumentNullException (nameof (types)); + } + + public ExpectedLocalsSequenceAttribute (Type[] types) + { + if (types == null) + throw new ArgumentNullException (nameof (types)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedNoWarningsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedNoWarningsAttribute.cs new file mode 100644 index 0000000000000..cd6e8f38667b2 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedNoWarningsAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field, + AllowMultiple = false, + Inherited = false)] + public class ExpectedNoWarningsAttribute : EnableLoggerAttribute + { + public ExpectedNoWarningsAttribute () { } + public ExpectedNoWarningsAttribute (string warningCode) { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs new file mode 100644 index 0000000000000..94d9f1c2cf725 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Assembly | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Event, + AllowMultiple = true, + Inherited = false)] + public class ExpectedWarningAttribute : EnableLoggerAttribute + { + public ExpectedWarningAttribute (string warningCode, params string[] messageContains) + { + } + + public string FileName { get; set; } + public int SourceLine { get; set; } + public int SourceColumn { get; set; } + + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// + public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAnalyzerAndNativeAot; + + public bool CompilerGeneratedCode { get; set; } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs new file mode 100644 index 0000000000000..78fd0e4537423 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class)] + public class IgnoreTestCaseAttribute : Attribute + { + + public IgnoreTestCaseAttribute (string reason) + { + if (reason == null) + throw new ArgumentNullException (nameof (reason)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAllTypesAndMembersInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAllTypesAndMembersInAssemblyAttribute.cs new file mode 100644 index 0000000000000..ffdb9d07c2e0a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAllTypesAndMembersInAssemblyAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class KeptAllTypesAndMembersInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptAllTypesAndMembersInAssemblyAttribute (string assemblyFileName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs new file mode 100644 index 0000000000000..9103fa1c31763 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that an assembly does exist in the output directory + /// + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class KeptAssemblyAttribute : KeptAttribute + { + + public KeptAssemblyAttribute (string fileName) + { + if (string.IsNullOrEmpty (fileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (fileName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs new file mode 100644 index 0000000000000..922123f7d11bd --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.All, Inherited = false)] + public class KeptAttribute : BaseExpectedLinkedBehaviorAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs new file mode 100644 index 0000000000000..0b5943a5a1a5e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)] + public class KeptAttributeAttribute : KeptAttribute + { + + public KeptAttributeAttribute (string attributeName) + { + if (string.IsNullOrEmpty (attributeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (attributeName)); + } + + public KeptAttributeAttribute (Type type) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..91081f68a1416 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeInAssemblyAttribute.cs @@ -0,0 +1,71 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptAttributeInAssemblyAttribute : BaseInAssemblyAttribute + { + /// + /// Asserts a CustomAttribute was kept on an assembly + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, string attributeTypeName) + { + } + + /// + /// Asserts a CustomAttribute was kept on an assembly + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, Type attributeType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a specific type + /// + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, string attributeTypeName, string onType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a specific type + /// + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, Type attributeType, Type onType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a member in a specific type + /// + /// + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, string attributeTypeName, string onType, string member) + { + } + + /// + /// Asserts a CustomAttribute was kept on a member in a specific type + /// + /// + /// + /// + /// + public KeptAttributeInAssemblyAttribute (string assemblyName, Type attributeType, Type onType, string member) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnFixedBufferTypeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnFixedBufferTypeAttribute.cs new file mode 100644 index 0000000000000..0fc56741a8ca4 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnFixedBufferTypeAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Field, Inherited = false, AllowMultiple = true)] + public class KeptAttributeOnFixedBufferTypeAttribute : KeptAttribute + { + public KeptAttributeOnFixedBufferTypeAttribute (string attributeName) + { + if (string.IsNullOrEmpty (attributeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (attributeName)); + } + + public KeptAttributeOnFixedBufferTypeAttribute (Type type) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs new file mode 100644 index 0000000000000..6994e1201f16e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = false, Inherited = false)] + public sealed class KeptBackingFieldAttribute : KeptAttribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseOnTypeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseOnTypeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..acac5d575bbce --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseOnTypeInAssemblyAttribute.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptBaseOnTypeInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptBaseOnTypeInAssemblyAttribute (string assemblyFileName, Type type, string baseAssemblyFileName, Type baseType) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + + if (string.IsNullOrEmpty (baseAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (baseAssemblyFileName)); + if (baseType == null) + throw new ArgumentException ("Value cannot be null or empty.", nameof (baseType)); + } + + public KeptBaseOnTypeInAssemblyAttribute (string assemblyFileName, string typeName, string baseAssemblyFileName, string baseTypeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + + if (string.IsNullOrEmpty (baseAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (baseAssemblyFileName)); + if (string.IsNullOrEmpty (baseTypeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (baseTypeName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs new file mode 100644 index 0000000000000..c4e4a24889542 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] + public sealed class KeptBaseTypeAttribute : KeptAttribute + { + public KeptBaseTypeAttribute (Type baseType) + { + if (baseType == null) + throw new ArgumentNullException (nameof (baseType)); + } + + public KeptBaseTypeAttribute (Type baseType, params object[] typeArguments) + { + if (baseType == null) + throw new ArgumentNullException (nameof (baseType)); + if (typeArguments == null) + throw new ArgumentNullException (nameof (typeArguments)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptDelegateCacheFieldAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptDelegateCacheFieldAttribute.cs new file mode 100644 index 0000000000000..52fe496182f8b --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptDelegateCacheFieldAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = true)] + public class KeptDelegateCacheFieldAttribute : KeptAttribute + { + public KeptDelegateCacheFieldAttribute (string uniquePartOfName) + { + if (string.IsNullOrEmpty (uniquePartOfName)) + throw new ArgumentNullException (nameof (uniquePartOfName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventAddMethodAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventAddMethodAttribute.cs new file mode 100644 index 0000000000000..2b745838c9666 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventAddMethodAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Event, Inherited = false, AllowMultiple = false)] + public class KeptEventAddMethodAttribute : KeptAttribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventRemoveMethodAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventRemoveMethodAttribute.cs new file mode 100644 index 0000000000000..0cbcdd171a91e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptEventRemoveMethodAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Event, Inherited = false, AllowMultiple = false)] + public class KeptEventRemoveMethodAttribute : KeptAttribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptExportedTypeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptExportedTypeAttribute.cs new file mode 100644 index 0000000000000..76dbe921c9457 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptExportedTypeAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that a module reference exists in the test case assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptExportedTypeAttribute : KeptAttribute + { + public KeptExportedTypeAttribute (Type type) + { + if (type is null) + throw new ArgumentNullException (nameof (type)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptFixedBufferAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptFixedBufferAttribute.cs new file mode 100644 index 0000000000000..d0067544ad760 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptFixedBufferAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Field, Inherited = false, AllowMultiple = false)] + public class KeptFixedBufferAttribute : KeptAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInitializerData.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInitializerData.cs new file mode 100644 index 0000000000000..25b8c8261f16c --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInitializerData.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Method, AllowMultiple = true, Inherited = false)] + public class KeptInitializerData : KeptAttribute + { + + public KeptInitializerData () + { + } + + public KeptInitializerData (int occurrenceIndexInBody) + { + if (occurrenceIndexInBody < 0) + throw new ArgumentOutOfRangeException (nameof (occurrenceIndexInBody)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs new file mode 100644 index 0000000000000..85279abcd83f6 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] + public class KeptInterfaceAttribute : KeptAttribute + { + + public KeptInterfaceAttribute (Type interfaceType) + { + if (interfaceType == null) + throw new ArgumentNullException (nameof (interfaceType)); + } + + public KeptInterfaceAttribute (Type interfaceType, params object[] typeArguments) + { + if (interfaceType == null) + throw new ArgumentNullException (nameof (interfaceType)); + if (typeArguments == null) + throw new ArgumentNullException (nameof (typeArguments)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceOnTypeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceOnTypeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..2741439facc88 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceOnTypeInAssemblyAttribute.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptInterfaceOnTypeInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptInterfaceOnTypeInAssemblyAttribute (string assemblyFileName, Type type, string interfaceAssemblyFileName, Type interfaceType) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + + if (string.IsNullOrEmpty (interfaceAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceAssemblyFileName)); + if (interfaceType == null) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceType)); + } + + public KeptInterfaceOnTypeInAssemblyAttribute (string assemblyFileName, string typeName, string interfaceAssemblyFileName, string interfaceTypeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + + if (string.IsNullOrEmpty (interfaceAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceAssemblyFileName)); + if (string.IsNullOrEmpty (interfaceTypeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceTypeName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs new file mode 100644 index 0000000000000..6f7adcf30bedb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)] + public sealed class KeptMemberAttribute : KeptAttribute + { + + public KeptMemberAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs new file mode 100644 index 0000000000000..b8e38f5788c05 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberInAssemblyAttribute.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class KeptMemberInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptMemberInAssemblyAttribute (string assemblyFileName, Type type, params string[] memberNames) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (memberNames == null) + throw new ArgumentNullException (nameof (memberNames)); + } + + public KeptMemberInAssemblyAttribute (string assemblyFileName, string typeName, params string[] memberNames) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (typeName == null) + throw new ArgumentNullException (nameof (typeName)); + if (memberNames == null) + throw new ArgumentNullException (nameof (memberNames)); + } + + public string ExpectationAssemblyName { get; set; } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptModuleReferenceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptModuleReferenceAttribute.cs new file mode 100644 index 0000000000000..4ebab7d971608 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptModuleReferenceAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that a module reference exists in the test case assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptModuleReferenceAttribute : KeptAttribute + { + public KeptModuleReferenceAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferenceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferenceAttribute.cs new file mode 100644 index 0000000000000..f4bb464260dba --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferenceAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that a reference exists in the test case assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptReferenceAttribute : KeptAttribute + { + public KeptReferenceAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferencesInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferencesInAssemblyAttribute.cs new file mode 100644 index 0000000000000..0265b9f3a40d9 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptReferencesInAssemblyAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptReferencesInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptReferencesInAssemblyAttribute (string assemblyFileName, string[] expectedReferenceAssemblyNames) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + + if (expectedReferenceAssemblyNames == null) + throw new ArgumentNullException (nameof (expectedReferenceAssemblyNames)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceAttribute.cs new file mode 100644 index 0000000000000..bcbbd20fb7253 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that a resource exists in the test case assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptResourceAttribute : KeptAttribute + { + public KeptResourceAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceInAssemblyAttribute.cs new file mode 100644 index 0000000000000..fa95216e3e3b5 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptResourceInAssemblyAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that an embedded resource exists in an assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptResourceInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptResourceInAssemblyAttribute (string assemblyFileName, string resourceName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + + if (string.IsNullOrEmpty (resourceName)) + throw new ArgumentNullException (nameof (resourceName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSecurityAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSecurityAttribute.cs new file mode 100644 index 0000000000000..05519377252dc --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSecurityAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly | AttributeTargets.Method, AllowMultiple = true, Inherited = false)] + public class KeptSecurityAttribute : KeptAttribute + { + public KeptSecurityAttribute (string attributeName) + { + if (string.IsNullOrEmpty (attributeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (attributeName)); + } + + public KeptSecurityAttribute (Type type) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSymbolsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSymbolsAttribute.cs new file mode 100644 index 0000000000000..3e435017b8b57 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptSymbolsAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class KeptSymbolsAttribute : KeptAttribute + { + public KeptSymbolsAttribute (string assemblyFileName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptTypeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptTypeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..5be0adc4aa108 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptTypeInAssemblyAttribute.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class KeptTypeInAssemblyAttribute : BaseInAssemblyAttribute + { + public KeptTypeInAssemblyAttribute (string assemblyFileName, Type type) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + } + + public KeptTypeInAssemblyAttribute (string assemblyFileName, string typeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs new file mode 100644 index 0000000000000..de9b8478bfd13 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field, + AllowMultiple = true, + Inherited = false)] + public class LogContainsAttribute : EnableLoggerAttribute + { + public LogContainsAttribute (string message, bool regexMatch = false) + { + if (string.IsNullOrEmpty (message)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); + } + + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// + public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAnalyzerAndNativeAot; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs new file mode 100644 index 0000000000000..c5b47210ed846 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field, + AllowMultiple = true, + Inherited = false)] + public class LogDoesNotContainAttribute : EnableLoggerAttribute + { + public LogDoesNotContainAttribute (string message, bool regexMatch = false) + { + if (string.IsNullOrEmpty (message)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); + } + + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// + public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAnalyzerAndNativeAot; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/NoLinkedOutputAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/NoLinkedOutputAttribute.cs new file mode 100644 index 0000000000000..85334c97da7ca --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/NoLinkedOutputAttribute.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class)] + public class NoLinkedOutputAttribute : Attribute + { + public NoLinkedOutputAttribute () { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ProducedBy.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ProducedBy.cs new file mode 100644 index 0000000000000..7840516cc242a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/ProducedBy.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Used to specify which tool produces a warning. This can either be the trimmer, a specific analyzer, or both. + /// Currently we have all existing diagnostic analyzers listed in here so that we can leave out some expected warnings + /// when testing analyzers which do not produce them. + /// + [Flags] + public enum ProducedBy + { + Trimmer = 1, + Analyzer = 2, + NativeAot = 4, + TrimmerAnalyzerAndNativeAot = Trimmer | Analyzer | NativeAot + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs new file mode 100644 index 0000000000000..e1dc4c0e1e36a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that an assembly does not exist in the output directory + /// + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class RemovedAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute + { + + public RemovedAssemblyAttribute (string fileName) + { + if (string.IsNullOrEmpty (fileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (fileName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyReference.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyReference.cs new file mode 100644 index 0000000000000..4bb914493a45d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyReference.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedAssemblyReferenceAttribute : BaseInAssemblyAttribute + { + public RemovedAssemblyReferenceAttribute (string assemblyFileName, string assemblyReferenceName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (assemblyReferenceName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyReferenceName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAttributeInAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAttributeInAssembly.cs new file mode 100644 index 0000000000000..591aa81b40f0e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAttributeInAssembly.cs @@ -0,0 +1,71 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedAttributeInAssembly : BaseInAssemblyAttribute + { + /// + /// Asserts a CustomAttribute was kept on an assembly + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, string attributeTypeName) + { + } + + /// + /// Asserts a CustomAttribute was kept on an assembly + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, Type attributeType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a specific type + /// + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, string attributeTypeName, string onType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a specific type + /// + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, Type attributeType, Type onType) + { + } + + /// + /// Asserts a CustomAttribute was kept on a member in a specific type + /// + /// + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, string attributeTypeName, string onType, string member) + { + } + + /// + /// Asserts a CustomAttribute was kept on a member in a specific type + /// + /// + /// + /// + /// + public RemovedAttributeInAssembly (string assemblyName, Type attributeType, Type onType, string member) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedForwarderAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedForwarderAttribute.cs new file mode 100644 index 0000000000000..eb9a394473623 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedForwarderAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedForwarderAttribute : BaseInAssemblyAttribute + { + public RemovedForwarderAttribute (string assemblyFileName, string typeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedInterfaceOnTypeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedInterfaceOnTypeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..70465fc3d6035 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedInterfaceOnTypeInAssemblyAttribute.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedInterfaceOnTypeInAssemblyAttribute : BaseInAssemblyAttribute + { + public RemovedInterfaceOnTypeInAssemblyAttribute (string assemblyFileName, Type type, string interfaceAssemblyFileName, Type interfaceType) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + + if (string.IsNullOrEmpty (interfaceAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceAssemblyFileName)); + if (interfaceType == null) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceType)); + } + + public RemovedInterfaceOnTypeInAssemblyAttribute (string assemblyFileName, string typeName, string interfaceAssemblyFileName, string interfaceTypeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + + if (string.IsNullOrEmpty (interfaceAssemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceAssemblyFileName)); + if (string.IsNullOrEmpty (interfaceTypeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (interfaceTypeName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs new file mode 100644 index 0000000000000..fe0deb6374aaf --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedMemberInAssemblyAttribute.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class RemovedMemberInAssemblyAttribute : BaseInAssemblyAttribute + { + + public RemovedMemberInAssemblyAttribute (string assemblyFileName, Type type, params string[] memberNames) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (memberNames == null) + throw new ArgumentNullException (nameof (memberNames)); + } + + public RemovedMemberInAssemblyAttribute (string assemblyFileName, string typeName, params string[] memberNames) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + if (typeName == null) + throw new ArgumentNullException (nameof (typeName)); + if (memberNames == null) + throw new ArgumentNullException (nameof (memberNames)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs new file mode 100644 index 0000000000000..027bd35955801 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedNameValueAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that name of the member is removed + /// + [AttributeUsage (AttributeTargets.All, AllowMultiple = false, Inherited = false)] + public class RemovedNameValueAttribute : BaseExpectedLinkedBehaviorAttribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedPseudoAttributeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedPseudoAttributeAttribute.cs new file mode 100644 index 0000000000000..00b4eb588eaf7 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedPseudoAttributeAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Interface | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event, AllowMultiple = true, Inherited = false)] + public class RemovedPseudoAttributeAttribute : BaseExpectedLinkedBehaviorAttribute + { + public RemovedPseudoAttributeAttribute (uint value) + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedResourceInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedResourceInAssemblyAttribute.cs new file mode 100644 index 0000000000000..5b793a034964d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedResourceInAssemblyAttribute.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + /// + /// Verifies that an embedded resource was removed from an assembly + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedResourceInAssemblyAttribute : BaseInAssemblyAttribute + { + public RemovedResourceInAssemblyAttribute (string assemblyFileName, string resourceName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentNullException (nameof (assemblyFileName)); + + if (string.IsNullOrEmpty (resourceName)) + throw new ArgumentNullException (nameof (resourceName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedSymbolsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedSymbolsAttribute.cs new file mode 100644 index 0000000000000..1549b8a03c9f1 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedSymbolsAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)] + public class RemovedSymbolsAttribute : BaseExpectedLinkedBehaviorAttribute + { + public RemovedSymbolsAttribute (string assemblyFileName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedTypeInAssemblyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedTypeInAssemblyAttribute.cs new file mode 100644 index 0000000000000..079ba5d1f0b7d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedTypeInAssemblyAttribute.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)] + public class RemovedTypeInAssemblyAttribute : BaseInAssemblyAttribute + { + public RemovedTypeInAssemblyAttribute (string assemblyFileName, Type type) + { + if (type == null) + throw new ArgumentNullException (nameof (type)); + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + } + + public RemovedTypeInAssemblyAttribute (string assemblyFileName, string typeName) + { + if (string.IsNullOrEmpty (assemblyFileName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (assemblyFileName)); + if (string.IsNullOrEmpty (typeName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeName)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipKeptItemsValidationAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipKeptItemsValidationAttribute.cs new file mode 100644 index 0000000000000..deb54564a8d0a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipKeptItemsValidationAttribute.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SkipKeptItemsValidationAttribute : BaseExpectedLinkedBehaviorAttribute + { + public SkipKeptItemsValidationAttribute () { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipPeVerifyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipPeVerifyAttribute.cs new file mode 100644 index 0000000000000..5b293eacdd349 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipPeVerifyAttribute.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + + public enum SkipPeVerifyForToolchian + { + Pedump + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SkipPeVerifyAttribute : BaseExpectedLinkedBehaviorAttribute + { + public SkipPeVerifyAttribute () + { + } + + public SkipPeVerifyAttribute (SkipPeVerifyForToolchian toolchain) + { + } + + public SkipPeVerifyAttribute (string assemblyName) + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipRemainingErrorsValidationAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipRemainingErrorsValidationAttribute.cs new file mode 100644 index 0000000000000..09174ab0577d0 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/SkipRemainingErrorsValidationAttribute.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SkipRemainingErrorsValidationAttribute : BaseExpectedLinkedBehaviorAttribute + { + public SkipRemainingErrorsValidationAttribute () { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestCaseRequirementsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestCaseRequirementsAttribute.cs new file mode 100644 index 0000000000000..9e766c9ce05c6 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestCaseRequirementsAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class)] + public class TestCaseRequirementsAttribute : BaseExpectedLinkedBehaviorAttribute + { + public TestCaseRequirementsAttribute (TestRunCharacteristics targetFrameworkCharacteristics, string reason) + { + if (reason == null) + throw new ArgumentNullException (nameof (reason)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestRunCharacteristics.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestRunCharacteristics.cs new file mode 100644 index 0000000000000..1e35a3dda0042 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/TestRunCharacteristics.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [Flags] + public enum TestRunCharacteristics + { + TargetingNetFramework = 1, + TargetingNetCore = 2, + SupportsDefaultInterfaceMethods = 8, + SupportsStaticInterfaceMethods = 16, + TestFrameworkSupportsMcs = 32 + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs new file mode 100644 index 0000000000000..bf42f4da0545f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Assertions/VerifyMetadataNamesAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class VerifyMetadataNamesAttribute : BaseExpectedLinkedBehaviorAttribute + { + public VerifyMetadataNamesAttribute () + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowStringExtensions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowStringExtensions.cs new file mode 100644 index 0000000000000..aa9c0b081f50a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowStringExtensions.cs @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics.CodeAnalysis; + +namespace Mono.Linker.Tests.Cases.Expectations.Helpers +{ + public static class DataFlowStringExtensions + { + public static void RequiresAll ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] this string str) { } + + public static void RequiresPublicConstructors ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] this string str) { } + + public static void RequiresPublicEvents ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] this string str) { } + + public static void RequiresPublicFields ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] this string str) { } + + public static void RequiresPublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] this string str) { } + + public static void RequiresPublicNestedTypes ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] this string str) { } + + public static void RequiresPublicParameterlessConstructor ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] this string str) { } + + public static void RequiresPublicProperties ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] this string str) { } + + public static void RequiresNonPublicEvents ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicEvents)] this string str) { } + + public static void RequiresNonPublicFields ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] this string str) { } + + public static void RequiresNonPublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] this string str) { } + + public static void RequiresNonPublicNestedTypes ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] this string str) { } + + public static void RequiresNonPublicConstructors ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] this string str) { } + + public static void RequiresNonPublicProperties ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicProperties)] this string str) { } + + public static void RequiresInterfaces ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] this string str) { } + + public static void RequiresNone (this string str) { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowTypeExtensions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowTypeExtensions.cs new file mode 100644 index 0000000000000..e11f78abe89ad --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/DataFlowTypeExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Mono.Linker.Tests.Cases.Expectations.Helpers +{ + public static class DataFlowTypeExtensions + { + public static void RequiresAll ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] this Type type) { } + + public static void RequiresPublicConstructors ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] this Type type) { } + + public static void RequiresPublicEvents ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] this Type type) { } + + public static void RequiresPublicFields ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] this Type type) { } + + public static void RequiresPublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] this Type type) { } + + public static void RequiresPublicNestedTypes ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] this Type type) { } + + public static void RequiresPublicParameterlessConstructor ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] this Type type) { } + + public static void RequiresPublicProperties ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] this Type type) { } + + public static void RequiresNonPublicEvents ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicEvents)] this Type type) { } + + public static void RequiresNonPublicFields ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] this Type type) { } + + public static void RequiresNonPublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] this Type type) { } + + public static void RequiresNonPublicNestedTypes ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] this Type type) { } + + public static void RequiresNonPublicConstructors ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] this Type type) { } + + public static void RequiresNonPublicProperties ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicProperties)] this Type type) { } + + public static void RequiresInterfaces ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] this Type type) { } + + public static void RequiresNone (this Type type) { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/PlatformAssemblies.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/PlatformAssemblies.cs new file mode 100644 index 0000000000000..c2e77e98f8d44 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Helpers/PlatformAssemblies.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Helpers +{ + public static class PlatformAssemblies + { +#if NETCOREAPP + public const string CoreLib = "System.Private.CoreLib.dll"; +#else + public const string CoreLib = "mscorlib.dll"; +#endif + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs new file mode 100644 index 0000000000000..d29e0a0ec6fad --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [Conditional ("INCLUDE_EXPECTATIONS")] + public abstract class BaseMetadataAttribute : Attribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/DefineAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/DefineAttribute.cs new file mode 100644 index 0000000000000..f0e34d1e68b4a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/DefineAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class DefineAttribute : BaseMetadataAttribute + { + public DefineAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (name)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreDescriptorsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreDescriptorsAttribute.cs new file mode 100644 index 0000000000000..ef1656e564c00 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreDescriptorsAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class IgnoreDescriptorsAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public IgnoreDescriptorsAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreLinkAttributesAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreLinkAttributesAttribute.cs new file mode 100644 index 0000000000000..0679c0f52d868 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreLinkAttributesAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class IgnoreLinkAttributesAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public IgnoreLinkAttributesAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreSubstitutionsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreSubstitutionsAttribute.cs new file mode 100644 index 0000000000000..613e9d8a908f7 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/IgnoreSubstitutionsAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class IgnoreSubstitutionsAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public IgnoreSubstitutionsAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/Il8nAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/Il8nAttribute.cs new file mode 100644 index 0000000000000..d79cdb37f1c2f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/Il8nAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class)] + public sealed class Il8nAttribute : BaseMetadataAttribute + { + public readonly string Value; + + public Il8nAttribute (string value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/KeepTypeForwarderOnlyAssembliesAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/KeepTypeForwarderOnlyAssembliesAttribute.cs new file mode 100644 index 0000000000000..e386d35024825 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/KeepTypeForwarderOnlyAssembliesAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class)] + public sealed class KeepTypeForwarderOnlyAssembliesAttribute : BaseMetadataAttribute + { + public KeepTypeForwarderOnlyAssembliesAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (value)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs new file mode 100644 index 0000000000000..a099ee6301a4b --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct)] + public class NotATestCaseAttribute : BaseMetadataAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs new file mode 100644 index 0000000000000..a704ea414e823 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class ReferenceAttribute : BaseMetadataAttribute + { + + public ReferenceAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (value)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceDependencyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceDependencyAttribute.cs new file mode 100644 index 0000000000000..c038fe43f7504 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceDependencyAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class ReferenceDependencyAttribute : BaseMetadataAttribute + { + public ReferenceDependencyAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (value)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs new file mode 100644 index 0000000000000..dce29bd3170bb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SandboxDependencyAttribute : BaseMetadataAttribute + { + + public SandboxDependencyAttribute (string relativePathToFile, string destinationFileName = null) + { + if (string.IsNullOrEmpty (relativePathToFile)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (relativePathToFile)); + } + + public SandboxDependencyAttribute (Type typeOfSourceFileToInclude, string destinationFileName = null) + { + if (typeOfSourceFileToInclude == null) + throw new ArgumentException ("Value cannot be null or empty.", nameof (typeOfSourceFileToInclude)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCSharpCompilerToUseAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCSharpCompilerToUseAttribute.cs new file mode 100644 index 0000000000000..277834153aaf9 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCSharpCompilerToUseAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupCSharpCompilerToUseAttribute : BaseMetadataAttribute + { + public SetupCSharpCompilerToUseAttribute (string name) + { + if (string.IsNullOrEmpty (name)) + throw new ArgumentNullException (nameof (name)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs new file mode 100644 index 0000000000000..71f9f7a3854bb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + /// + /// Use to compile an assembly after compiling the main test case executabe + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupCompileAfterAttribute : BaseMetadataAttribute + { + public SetupCompileAfterAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) + { + if (sourceFiles == null) + throw new ArgumentNullException (nameof (sourceFiles)); + + if (string.IsNullOrEmpty (outputName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileArgumentAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileArgumentAttribute.cs new file mode 100644 index 0000000000000..67020707d814d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileArgumentAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupCompileArgumentAttribute : BaseMetadataAttribute + { + public SetupCompileArgumentAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentNullException (nameof (value)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAsLibraryAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAsLibraryAttribute.cs new file mode 100644 index 0000000000000..e78aaa089bcc3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAsLibraryAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupCompileAsLibraryAttribute : BaseMetadataAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAssemblyNameAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAssemblyNameAttribute.cs new file mode 100644 index 0000000000000..7fad90431149d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAssemblyNameAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupCompileAssemblyNameAttribute : BaseMetadataAttribute + { + public SetupCompileAssemblyNameAttribute (string outputName) + { + if (string.IsNullOrEmpty (outputName)) + throw new ArgumentNullException (nameof (outputName)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs new file mode 100644 index 0000000000000..0021300c8403e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + /// + /// Use to compile an assembly before compiling the main test case executabe + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupCompileBeforeAttribute : BaseMetadataAttribute + { + public SetupCompileBeforeAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false, string outputSubFolder = null) + { + if (sourceFiles == null) + throw new ArgumentNullException (nameof (sourceFiles)); + + if (string.IsNullOrEmpty (outputName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } + } + + public SetupCompileBeforeAttribute (string outputName, Type[] typesToIncludeSourceFor, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) + { + if (typesToIncludeSourceFor == null) + throw new ArgumentNullException (nameof (typesToIncludeSourceFor)); + + if (string.IsNullOrEmpty (outputName)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileResourceAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileResourceAttribute.cs new file mode 100644 index 0000000000000..83a7f11c57e61 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileResourceAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupCompileResourceAttribute : BaseMetadataAttribute + { + public SetupCompileResourceAttribute (string relativePathToFile, string destinationFileName = null) + { + if (string.IsNullOrEmpty (relativePathToFile)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (relativePathToFile)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkAttributesFile.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkAttributesFile.cs new file mode 100644 index 0000000000000..1c55f9946e658 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkAttributesFile.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkAttributesFile : BaseMetadataAttribute + { + public SetupLinkAttributesFile (string relativePathToFile, string destinationFileName = null) + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerActionAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerActionAttribute.cs new file mode 100644 index 0000000000000..bc78fc9346ff7 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerActionAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkerActionAttribute : BaseMetadataAttribute + { + public SetupLinkerActionAttribute (string action, string assembly) + { + if (string.IsNullOrEmpty (action)) + throw new ArgumentNullException (nameof (action)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerArgumentAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerArgumentAttribute.cs new file mode 100644 index 0000000000000..6f2e55f24bba2 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerArgumentAttribute.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + + /// + /// Used to define arguments to pass to the linker. + /// + /// Don't use this attribute to setup single character flags. These flags do a poor job of communicating their purpose + /// and although we need to continue to support the usages that exist today, that doesn't mean we need to make our tests harder to read + /// + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkerArgumentAttribute : BaseMetadataAttribute + { + public SetupLinkerArgumentAttribute (string flag, params string[] values) + { + if (string.IsNullOrEmpty (flag)) + throw new ArgumentNullException (nameof (flag)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDefaultActionAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDefaultActionAttribute.cs new file mode 100644 index 0000000000000..ee9794d495f98 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDefaultActionAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupLinkerDefaultActionAttribute : BaseMetadataAttribute + { + public SetupLinkerDefaultActionAttribute (string action) + { + if (string.IsNullOrEmpty (action)) + throw new ArgumentNullException (nameof (action)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDescriptorFile.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDescriptorFile.cs new file mode 100644 index 0000000000000..e1c7c4501dc15 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerDescriptorFile.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkerDescriptorFile : BaseMetadataAttribute + { + public SetupLinkerDescriptorFile (string relativePathToFile, string destinationFileName = null) + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerKeepDebugMembersAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerKeepDebugMembersAttribute.cs new file mode 100644 index 0000000000000..2213b9cc551c7 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerKeepDebugMembersAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class)] + public class SetupLinkerKeepDebugMembersAttribute : BaseMetadataAttribute + { + public SetupLinkerKeepDebugMembersAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (value)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkPublicAndFamilyAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkPublicAndFamilyAttribute.cs new file mode 100644 index 0000000000000..c4250b82e231d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkPublicAndFamilyAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupLinkerLinkPublicAndFamilyAttribute : BaseMetadataAttribute + { + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkSymbolsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkSymbolsAttribute.cs new file mode 100644 index 0000000000000..5aa97e2ca05e2 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerLinkSymbolsAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class)] + public class SetupLinkerLinkSymbolsAttribute : BaseMetadataAttribute + { + public SetupLinkerLinkSymbolsAttribute (string value) + { + if (string.IsNullOrEmpty (value)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (value)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerResponseFileAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerResponseFileAttribute.cs new file mode 100644 index 0000000000000..28c30f868bcda --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerResponseFileAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkerResponseFileAttribute : BaseMetadataAttribute + { + public SetupLinkerResponseFileAttribute (string relativePathToFile, string destinationFileName = null) + { + if (string.IsNullOrEmpty (relativePathToFile)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (relativePathToFile)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerSubstitutionFileAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerSubstitutionFileAttribute.cs new file mode 100644 index 0000000000000..6a102a830fa16 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerSubstitutionFileAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] + public class SetupLinkerSubstitutionFileAttribute : BaseMetadataAttribute + { + public SetupLinkerSubstitutionFileAttribute (string relativePathToFile, string destinationFileName = null) + { + if (string.IsNullOrEmpty (relativePathToFile)) + throw new ArgumentException ("Value cannot be null or empty.", nameof (relativePathToFile)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerTrimModeAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerTrimModeAttribute.cs new file mode 100644 index 0000000000000..e303447291f56 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupLinkerTrimModeAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SetupLinkerTrimModeAttribute : BaseMetadataAttribute + { + public SetupLinkerTrimModeAttribute (string action) + { + if (string.IsNullOrEmpty (action)) + throw new ArgumentNullException (nameof (action)); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs new file mode 100644 index 0000000000000..37fbce0e04cf1 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class SkipUnresolvedAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public SkipUnresolvedAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripDescriptorsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripDescriptorsAttribute.cs new file mode 100644 index 0000000000000..704d01971f3d5 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripDescriptorsAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class StripDescriptorsAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public StripDescriptorsAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripLinkAttributesAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripLinkAttributesAttribute.cs new file mode 100644 index 0000000000000..4f2380fb93884 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripLinkAttributesAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class StripLinkAttributesAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public StripLinkAttributesAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripSubstitutionsAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripSubstitutionsAttribute.cs new file mode 100644 index 0000000000000..1f0732216640f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Metadata/StripSubstitutionsAttribute.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata +{ + public sealed class StripSubstitutionsAttribute : BaseMetadataAttribute + { + public readonly bool Value; + + public StripSubstitutionsAttribute (bool value) + { + Value = value; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj new file mode 100644 index 0000000000000..14a94ab30bf27 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj @@ -0,0 +1,10 @@ + + + + $(NetCoreAppToolCurrent) + disable + x64;x86 + AnyCPU + + + diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/IntrinsicAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/IntrinsicAttribute.cs new file mode 100644 index 0000000000000..4c2153dbff35e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/IntrinsicAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Runtime.CompilerServices +{ + // This attribute is normally implemented in CoreLib as internal, but in order to test + // linker behavior around it, we need to be able to use it in the tests. + [AttributeUsage (AttributeTargets.Method)] + public sealed class IntrinsicAttribute : Attribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/RemoveAttributeInstancesAttribute.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/RemoveAttributeInstancesAttribute.cs new file mode 100644 index 0000000000000..e2eb936d545f8 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases.Expectations/Support/RemoveAttributeInstancesAttribute.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker +{ + /// + /// This attribute name will be the name hardcoded in linker which will remove all + /// attribute usages but not the attribute definition + /// + [AttributeUsage ( + AttributeTargets.Class, Inherited = false)] + public sealed class RemoveAttributeInstancesAttribute : Attribute + { + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs new file mode 100644 index 0000000000000..e2df9679801a4 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs @@ -0,0 +1,163 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + // Note: this test's goal is to validate that the product correctly reports unrecognized patterns + // - so the main validation is done by the ExpectedWarning attributes. + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class AssemblyQualifiedNameDataflow + { + static void Main () + { + TestPublicParameterlessConstructor (); + TestPublicConstructors (); + TestConstructors (); + TestUnqualifiedTypeNameWarns (); + TestNull (); + TestMultipleValues (); + TestUnknownValue (); + TestNoValue (); + TestObjectGetTypeValue (); + } + + [ExpectedWarning ("IL2072", nameof (RequirePublicConstructors))] + [ExpectedWarning ("IL2072", nameof (RequireNonPublicConstructors))] + static void TestPublicParameterlessConstructor () + { + string type = GetTypeWithPublicParameterlessConstructor ().AssemblyQualifiedName; + RequirePublicParameterlessConstructor (type); + RequirePublicConstructors (type); + RequireNonPublicConstructors (type); + RequireNothing (type); + } + + [ExpectedWarning ("IL2072", nameof (RequireNonPublicConstructors))] + static void TestPublicConstructors () + { + string type = GetTypeWithPublicConstructors ().AssemblyQualifiedName; + RequirePublicParameterlessConstructor (type); + RequirePublicConstructors (type); + RequireNonPublicConstructors (type); + RequireNothing (type); + } + + [ExpectedWarning ("IL2072", nameof (RequirePublicParameterlessConstructor))] + [ExpectedWarning ("IL2072", nameof (RequirePublicConstructors))] + static void TestConstructors () + { + string type = GetTypeWithNonPublicConstructors ().AssemblyQualifiedName; + RequirePublicParameterlessConstructor (type); + RequirePublicConstructors (type); + RequireNonPublicConstructors (type); + RequireNothing (type); + } + + [ExpectedWarning ("IL2105", + "Type 'System.Invalid.TypeName' 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.", + ProducedBy = ProducedBy.Trimmer)] + static void TestUnqualifiedTypeNameWarns () + { + RequirePublicConstructors ("System.Invalid.TypeName"); + } + + static void TestNull () + { + Type type = null; + RequirePublicConstructors (type.AssemblyQualifiedName); // Null should not warn - we know it's going to fail at runtime + } + + [ExpectedWarning ("IL2072", nameof (RequirePublicConstructors), nameof (GetTypeWithNonPublicConstructors))] + [ExpectedWarning ("IL2062", nameof (RequirePublicConstructors))] + static void TestMultipleValues (int p = 0, object[] o = null) + { + Type type = p switch { + 0 => GetTypeWithPublicConstructors (), + 1 => GetTypeWithNonPublicConstructors (), // Should produce warning IL2072 due to mismatch annotation + 2 => null, // Should be ignored + _ => (Type) o[0] // This creates an unknown value - should produce warning IL2062 + }; + + RequirePublicConstructors (type.AssemblyQualifiedName); + } + + [ExpectedWarning ("IL2062", nameof (RequirePublicConstructors))] + static void TestUnknownValue (object[] o = null) + { + string unknown = ((Type) o[0]).AssemblyQualifiedName; + RequirePublicConstructors (unknown); + RequireNothing (unknown); // shouldn't warn + } + + static void TestNoValue () + { + Type t = null; + Type noValue = Type.GetTypeFromHandle (t.TypeHandle); + // t.TypeHandle throws at runtime so don't warn here. + RequirePublicConstructors (noValue.AssemblyQualifiedName); + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + class AnnotatedType + { + } + + static void TestObjectGetTypeValue (AnnotatedType instance = null) + { + string type = instance.GetType ().AssemblyQualifiedName; + // Currently Object.GetType is unimplemented in the analyzer, but + // this still shouldn't warn. + RequirePublicConstructors (type); + RequireNothing (type); + } + + private static void RequirePublicParameterlessConstructor ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + string type) + { + } + + private static void RequirePublicConstructors ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + string type) + { + } + + private static void RequireNonPublicConstructors ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] + string type) + { + } + + private static void RequireNothing (string type) + { + } + + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + private static Type GetTypeWithPublicParameterlessConstructor () + { + return null; + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + private static Type GetTypeWithPublicConstructors () + { + return null; + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] + private static Type GetTypeWithNonPublicConstructors () + { + return null; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs new file mode 100644 index 0000000000000..268466a3b427d --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + // Note: this test's goal is to validate that the product correctly reports unrecognized patterns + // - so the main validation is done by the ExpectedWarning attributes. + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class EmptyArrayIntrinsicsDataFlow + { + static void Main () + { + TestGetPublicParameterlessConstructorWithEmptyTypes (); + TestGetPublicParameterlessConstructorWithArrayEmpty (); + TestGetPublicParameterlessConstructorWithUnknownArray (); + TestGetConstructorOverloads (); + } + + [ExpectedWarning ("IL2080", nameof (Type.GetMethod))] + static void TestGetPublicParameterlessConstructorWithEmptyTypes () + { + s_typeWithKeptPublicParameterlessConstructor.GetConstructor (Type.EmptyTypes); + s_typeWithKeptPublicParameterlessConstructor.GetMethod ("Foo"); + } + + [ExpectedWarning ("IL2080", nameof (Type.GetMethod))] + static void TestGetPublicParameterlessConstructorWithArrayEmpty () + { + s_typeWithKeptPublicParameterlessConstructor.GetConstructor (Array.Empty ()); + s_typeWithKeptPublicParameterlessConstructor.GetMethod ("Foo"); + } + + [ExpectedWarning ("IL2080", nameof (Type.GetConstructor))] + static void TestGetPublicParameterlessConstructorWithUnknownArray () + { + s_typeWithKeptPublicParameterlessConstructor.GetConstructor (s_localEmptyArrayInvisibleToAnalysis); + } + + [ExpectedWarning ("IL2080", nameof (Type.GetMethod))] + static void TestGetConstructorOverloads () + { + s_typeWithKeptPublicParameterlessConstructor.GetConstructor (BindingFlags.Public, null, Type.EmptyTypes, null); + s_typeWithKeptPublicParameterlessConstructor.GetConstructor (BindingFlags.Public, null, CallingConventions.Any, Type.EmptyTypes, null); + s_typeWithKeptPublicParameterlessConstructor.GetMethod ("Foo"); + } + + static Type[] s_localEmptyArrayInvisibleToAnalysis = Type.EmptyTypes; + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + static Type s_typeWithKeptPublicParameterlessConstructor = typeof (EmptyArrayIntrinsicsDataFlow); + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs new file mode 100644 index 0000000000000..a369157dbbc82 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetInterfaceDataFlow.cs @@ -0,0 +1,198 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class GetInterfaceDataFlow + { + public static void Main () + { + GetInterface_Name.Test (); + GetInterface_Name_IgnoreCase.Test (); + } + + class GetInterface_Name + { + static void TestNullName (Type type) + { + type.GetInterface (null); + } + + static void TestEmptyName (Type type) + { + type.GetInterface (string.Empty); + } + + static void TestNoValueName (Type type) + { + Type t = null; + string noValue = t.AssemblyQualifiedName; + type.GetInterface (noValue); + } + + [ExpectedWarning ("IL2070", nameof (Type.GetInterface), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces))] + static void TestNoAnnotation (Type type) + { + type.GetInterface ("ITestInterface"); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestWithAnnotation ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] Type type) + { + type.GetInterface ("ITestInterface").RequiresInterfaces (); + type.GetInterface ("ITestInterface").RequiresAll (); // Warns + } + + static void TestWithAll ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type type) + { + type.GetInterface ("ITestInterface").RequiresInterfaces (); + type.GetInterface ("ITestInterface").RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestKnownType () + { + // Interfaces marking is transitive - meaning that it marks all interfaces in the entire hierarchy + // so the return value of GetInterface always has all interfaces on it already. + typeof (TestType).GetInterface ("ITestInterface").RequiresInterfaces (); + typeof (TestType).GetInterface ("ITestInterface").RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestMultipleValues (int p, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeWithAll) + { + Type type; + if (p == 0) + type = typeof (TestType); + else + type = typeWithAll; + + type.GetInterface ("ITestInterface").RequiresInterfaces (); + type.GetInterface ("ITestInterface").RequiresAll (); // Warns since only one of the values is guaranteed All + } + + [ExpectedWarning ("IL2075", nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces))] + static void TestMergedValues (int p, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeWithAll) + { + Type type = new TestType ().GetType (); + if (p == 0) { + type = typeWithAll; + } + + type.GetInterface ("ITestInterface").RequiresInterfaces (); + } + + static void TestNullValue () + { + Type t = null; + t.GetInterface ("ITestInterface").RequiresInterfaces (); + } + + static void TestNoValue () + { + Type t = null; + Type noValue = Type.GetTypeFromHandle (t.TypeHandle); + // t.TypeHandle throws at runtime so don't warn here. + noValue.GetInterface ("ITestInterface").RequiresInterfaces (); + } + + class GetInterfaceInCtor + { + public GetInterfaceInCtor ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] Type type) + { + type.GetInterface ("ITestInterface").RequiresInterfaces (); + } + } + + public static void Test () + { + TestNullName (typeof (TestType)); + TestEmptyName (typeof (TestType)); + TestNoValueName (typeof (TestType)); + TestNoAnnotation (typeof (TestType)); + TestWithAnnotation (typeof (TestType)); + TestWithAnnotation (typeof (ITestInterface)); + TestWithAll (typeof (TestType)); + TestKnownType (); + TestMultipleValues (0, typeof (TestType)); + TestMergedValues (0, typeof (TestType)); + TestNullValue (); + TestNoValue (); + var _ = new GetInterfaceInCtor (typeof (TestType)); + } + } + + class GetInterface_Name_IgnoreCase + { + [ExpectedWarning ("IL2070", nameof (Type.GetInterface), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces))] + static void TestNoAnnotation (Type type) + { + type.GetInterface ("ITestInterface", false); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestWithAnnotation ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] Type type) + { + type.GetInterface ("ITestInterface", false).RequiresInterfaces (); + type.GetInterface ("ITestInterface", false).RequiresAll (); // Warns + } + + static void TestWithAll ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type type) + { + type.GetInterface ("ITestInterface", false).RequiresInterfaces (); + type.GetInterface ("ITestInterface", false).RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestKnownType () + { + // Interfaces marking is transitive - meaning that it marks all interfaces in the entire hierarchy + // so the return value of GetInterface always has all interfaces on it already. + typeof (TestType).GetInterface ("ITestInterface", false).RequiresInterfaces (); + typeof (TestType).GetInterface ("ITestInterface", false).RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestMultipleValues (int p, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type typeWithAll) + { + Type type; + if (p == 0) + type = typeof (TestType); + else + type = typeWithAll; + + type.GetInterface ("ITestInterface", false).RequiresInterfaces (); + type.GetInterface ("ITestInterface", false).RequiresAll (); // Warns since only one of the values is guaranteed All + } + + public static void Test () + { + TestNoAnnotation (typeof (TestType)); + TestWithAnnotation (typeof (TestType)); + TestWithAnnotation (typeof (ITestInterface)); + TestWithAll (typeof (TestType)); + TestKnownType (); + TestMultipleValues (0, typeof (TestType)); + } + } + + interface ITestInterface + { + } + + class TestType : ITestInterface + { + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetNestedTypeOnAllAnnotatedType.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetNestedTypeOnAllAnnotatedType.cs new file mode 100644 index 0000000000000..d8f14b71eb70f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetNestedTypeOnAllAnnotatedType.cs @@ -0,0 +1,141 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [ExpectedNoWarnings] + [SkipKeptItemsValidation] + class GetNestedTypeOnAllAnnotatedType + { + static void Main () + { + TestOnAllAnnotatedParameter (typeof (TestType)); + TestOnNonAllAnnotatedParameter (typeof (TestType)); + TestWithBindingFlags (typeof (TestType)); + TestWithUnknownBindingFlags (BindingFlags.Public, typeof (TestType)); + TestUnsupportedBindingFlags (typeof (TestType)); + TestWithNull (); + TestWithEmptyInput (); + TestIfElse (1, typeof (TestType), typeof (TestType)); + TestSwitchAllValid (1, typeof (TestType)); + TestOnKnownTypeOnly (); + TestOnKnownTypeWithNullName (); + TestOnKnownTypeWithUnknownName ("noname"); + TestWithKnownTypeAndNameWhichDoesntExist (); + } + + static void TestOnAllAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentType) + { + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType)); + nestedType.RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestOnNonAllAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] Type parentType) + { + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType)); + nestedType.RequiresAll (); + } + + static void TestWithBindingFlags ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentType) + { + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType), BindingFlags.Public); + nestedType.RequiresAll (); + } + + static void TestWithUnknownBindingFlags (BindingFlags bindingFlags, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentType) + { + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType), bindingFlags); + nestedType.RequiresAll (); + } + + static void TestUnsupportedBindingFlags ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentType) + { + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType), BindingFlags.IgnoreCase); + nestedType.RequiresAll (); + } + + static void TestWithNull () + { + Type parentType = null; + var nestedType = parentType.GetNestedType (nameof (TestType.NestedType)); + nestedType.RequiresAll (); + } + + static void TestWithEmptyInput () + { + Type t = null; + Type noValue = Type.GetTypeFromHandle (t.TypeHandle); // Throws at runtime -> tracked as empty value set + noValue.GetNestedType (nameof (TestType.NestedType)).RequiresAll (); // No warning - empty input + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestIfElse (int number, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentWithAll, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] Type parentWithoutAll) + { + Type typeOfParent; + if (number == 1) { + typeOfParent = parentWithAll; + } else { + typeOfParent = parentWithoutAll; + } + var nestedType = typeOfParent.GetNestedType (nameof (TestType.NestedType)); + nestedType.RequiresAll (); + } + + static void TestSwitchAllValid (int number, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type parentWithAll) + { + Type typeOfParent = number switch { + 1 => parentWithAll, + 2 => null, + 3 => typeof (TestType) + }; + + var nestedType = typeOfParent.GetNestedType (nameof (TestType.NestedType)); + nestedType.RequiresAll (); + } + + static void TestOnKnownTypeOnly () + { + typeof (TestType).GetNestedType (nameof (TestType.NestedType)).RequiresAll (); + } + + static void TestOnKnownTypeWithNullName () + { + typeof (TestType).GetNestedType (null).RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestOnKnownTypeWithUnknownName (string name) + { + // WARN - we will preserve the nested type, but not as a whole, just the type itself, so it can't fullfil the All annotation + typeof (TestType).GetNestedType (name).RequiresAll (); + } + + static void TestWithKnownTypeAndNameWhichDoesntExist () + { + // Should not warn since we can statically determine that GetNestedType will return null so there's no problem with trimming + typeof (TestType).GetNestedType ("NonExisting").RequiresAll (); + } + + class TestType + { + public class NestedType + { + NestedType () { } + public static int PublicStaticInt; + public void Method () { } + int Prop { get; set; } + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs new file mode 100644 index 0000000000000..ef58eac310f4f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -0,0 +1,220 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + // Note: this test's goal is to validate that the product correctly reports unrecognized patterns + // - so the main validation is done by the ExpectedWarning attributes. + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class GetTypeDataFlow + { + public static void Main () + { + TestPublicParameterlessConstructor (); + TestPublicConstructors (); + TestConstructors (); + TestNull (); + TestNoValue (); + TestUnknownType (); + + TestTypeNameFromParameter (null); + TestTypeNameFromField (); + + TestMultipleConstantValues (); + TestMultipleMixedValues (); + + TestStringEmpty (); + + TypeWithWarnings.Test (); + OverConstTypeName.Test (); + + // TODO: + // Test multi-value returns + // Type.GetType over a constant and a param + // Type.GetType over two params + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicConstructors))] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors))] + static void TestPublicParameterlessConstructor () + { + Type type = Type.GetType (GetStringTypeWithPublicParameterlessConstructor ()); + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); + type.RequiresNonPublicConstructors (); + type.RequiresNone (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors))] + static void TestPublicConstructors () + { + Type type = Type.GetType (GetStringTypeWithPublicConstructors ()); + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); + type.RequiresNonPublicConstructors (); + type.RequiresNone (); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicParameterlessConstructor))] + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicConstructors))] + static void TestConstructors () + { + Type type = Type.GetType (GetStringTypeWithNonPublicConstructors ()); + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); + type.RequiresNonPublicConstructors (); + type.RequiresNone (); + } + + static void TestNull () + { + // GetType(null) throws at runtime, so we "give up" on analysis + Type.GetType (null).RequiresAll (); + } + + static void TestNoValue () + { + Type t = null; + // null.AssemblyQualifiedName throws at runtime, so we "give up" on analysis + string noValue = t.AssemblyQualifiedName; + Type.GetType (noValue).RequiresAll (); + } + + [ExpectedWarning ("IL2057", nameof (GetType))] + static void TestUnknownType () + { + Type type = Type.GetType (GetStringUnkownType ()); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicConstructors))] + static void TestTypeNameFromParameter ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + string typeName) + { + Type.GetType (typeName).RequiresPublicConstructors (); + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + static string _typeNameWithPublicParameterlessConstructor; + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresPublicConstructors))] + static void TestTypeNameFromField () + { + Type.GetType (_typeNameWithPublicParameterlessConstructor).RequiresPublicConstructors (); + } + + static int _switchOnField; + + static void TestMultipleConstantValues () + { + string typeName = null; + switch (_switchOnField) { + case 0: // valid + typeName = "Mono.Linker.Tests.Cases.DataFlow.GetTypeDataFlow"; + break; + case 1: // null + typeName = null; + break; + case 2: // invalid + typeName = "UnknownType"; + break; + case 3: // invalid second + typeName = "AnotherUnknownType"; + break; + } + + Type.GetType (typeName); + } + + static void TestStringEmpty () + { + Type.GetType (string.Empty); + } + + [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors), nameof (Type.GetType))] + [ExpectedWarning ("IL2057", "System.Type.GetType(String)")] + static void TestMultipleMixedValues () + { + string typeName = null; + switch (_switchOnField) { + case 0: + typeName = GetStringTypeWithPublicParameterlessConstructor (); + break; + case 1: + typeName = GetStringTypeWithNonPublicConstructors (); + break; + case 2: + typeName = "Mono.Linker.Tests.Cases.DataFlow.GetTypeDataFlow"; + break; + case 3: + typeName = GetStringUnkownType (); + break; + } + + Type.GetType (typeName).RequiresNonPublicConstructors (); + } + + class TypeWithWarnings + { + [RequiresUnreferencedCode ("--Method1--")] + public void Method1 () { } + + [RequiresUnreferencedCode ("--Method2--")] + public void Method2 () { } + + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "--Method2--", ProducedBy = ProducedBy.Trimmer)] + public static void Test () + { + Type.GetType ("Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (TypeWithWarnings)).RequiresPublicMethods (); + } + } + + class OverConstTypeName + { + private const string s_ConstTypeName = "Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (OverConstTypeName); + + [RequiresUnreferencedCode ("--Method1--")] + public void Method1 () { } + + // https://github.com/dotnet/linker/issues/2273 + [ExpectedWarning ("IL2026", "--Method1--", ProducedBy = ProducedBy.Trimmer)] + public static void Test () + { + Type.GetType (s_ConstTypeName).RequiresPublicMethods (); + } + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + private static string GetStringTypeWithPublicParameterlessConstructor () + { + return null; + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + private static string GetStringTypeWithPublicConstructors () + { + return null; + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] + private static string GetStringTypeWithNonPublicConstructors () + { + return null; + } + + private static string GetStringUnkownType () + { + return null; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeInfoDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeInfoDataFlow.cs new file mode 100644 index 0000000000000..29c25403e615b --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/GetTypeInfoDataFlow.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class GetTypeInfoDataFlow + { + public static void Main () + { + TestNoAnnotations (typeof (TestType)); + TestWithAnnotations (typeof (TestType)); + TestWithNull (); + TestWithNoValue (); + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestNoAnnotations (Type t) + { + t.GetTypeInfo ().RequiresPublicMethods (); + t.GetTypeInfo ().RequiresNone (); + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicFields))] + static void TestWithAnnotations ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) + { + t.GetTypeInfo ().RequiresPublicMethods (); + t.GetTypeInfo ().RequiresPublicFields (); + t.GetTypeInfo ().RequiresNone (); + } + + static void TestWithNull () + { + Type t = null; + t.GetTypeInfo ().RequiresPublicMethods (); + } + + static void TestWithNoValue () + { + Type t = null; + Type noValue = Type.GetTypeFromHandle (t.TypeHandle); + noValue.GetTypeInfo ().RequiresPublicMethods (); + } + + class TestType { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/MemberTypesRelationships.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/MemberTypesRelationships.cs new file mode 100644 index 0000000000000..7ae4a6ac5e8dd --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/MemberTypesRelationships.cs @@ -0,0 +1,275 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class MemberTypesRelationships + { + public static void Main () + { + TestPublicParameterlessConstructor (typeof (TestType)); + TestPublicConstructors (typeof (TestType)); + TestNonPublicConstructors (typeof (TestType)); + TestPublicMethods (typeof (TestType)); + TestNonPublicMethods (typeof (TestType)); + TestPublicFields (typeof (TestType)); + TestNonPublicFields (typeof (TestType)); + TestPublicNestedTypes (typeof (TestType)); + TestNonPublicNestedTypes (typeof (TestType)); + TestPublicProperties (typeof (TestType)); + TestNonPublicProperties (typeof (TestType)); + TestPublicEvents (typeof (TestType)); + TestNonPublicEvents (typeof (TestType)); + TestInterfaces (typeof (TestType)); + TestAll (typeof (TestType)); + TestMultiple (typeof (TestType)); + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicMethods))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicParameterlessConstructor ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) + { + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); // Warns + type.RequiresNonPublicConstructors (); // Warns + type.RequiresNone (); + type.RequiresPublicMethods (); // Warns + type.RequiresAll (); // Warns + } + + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicMethods))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicConstructors ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); + type.RequiresNonPublicConstructors (); // Warns + type.RequiresNone (); + type.RequiresPublicMethods (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicParameterlessConstructor), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicMethods))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicConstructors ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type) + { + type.RequiresPublicParameterlessConstructor (); // Warns + type.RequiresPublicConstructors (); // Warns + type.RequiresNonPublicConstructors (); + type.RequiresNone (); + type.RequiresPublicMethods (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicMethods), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicMethods))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicConstructors), "y '" + nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicConstructors) + "' i")] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + type.RequiresPublicMethods (); + type.RequiresNonPublicMethods (); // Warns + type.RequiresNone (); + type.RequiresPublicConstructors (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicMethods))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type) + { + type.RequiresPublicMethods (); // Warns + type.RequiresNonPublicMethods (); + type.RequiresNone (); + type.RequiresNonPublicConstructors (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) + { + type.RequiresPublicFields (); + type.RequiresNonPublicFields (); // Warns + type.RequiresNone (); + type.RequiresPublicConstructors (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicConstructors))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) + { + type.RequiresPublicFields (); // Warns + type.RequiresNonPublicFields (); + type.RequiresNone (); + type.RequiresNonPublicConstructors (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicNestedTypes), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicNestedTypes))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresInterfaces), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicNestedTypes ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] Type type) + { + type.RequiresPublicNestedTypes (); + type.RequiresNonPublicNestedTypes (); // Warns + type.RequiresNone (); + type.RequiresInterfaces (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicNestedTypes), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicNestedTypes))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresInterfaces), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicNestedTypes ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] Type type) + { + type.RequiresPublicNestedTypes (); // Warns + type.RequiresNonPublicNestedTypes (); + type.RequiresNone (); + type.RequiresInterfaces (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicProperties), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicProperties))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicProperties ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] Type type) + { + type.RequiresPublicProperties (); + type.RequiresNonPublicProperties (); // Warns + type.RequiresNone (); + type.RequiresPublicFields (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicProperties), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicProperties))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicProperties ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type) + { + type.RequiresPublicProperties (); // Warns + type.RequiresNonPublicProperties (); + type.RequiresNone (); + type.RequiresNonPublicFields (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicEvents), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicEvents))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestPublicEvents ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] Type type) + { + type.RequiresPublicEvents (); + type.RequiresNonPublicEvents (); // Warns + type.RequiresNone (); + type.RequiresPublicFields (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicEvents), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicEvents))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicFields), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicFields))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestNonPublicEvents ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicEvents)] Type type) + { + type.RequiresPublicEvents (); // Warns + type.RequiresNonPublicEvents (); + type.RequiresNone (); + type.RequiresNonPublicFields (); // Warns + type.RequiresAll (); // Warns + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicNestedTypes), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.PublicNestedTypes))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresNonPublicNestedTypes), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicNestedTypes))] + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresAll), nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.All))] + static void TestInterfaces ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] Type type) + { + type.RequiresInterfaces (); + type.RequiresNone (); + type.RequiresPublicNestedTypes (); // Warns + type.RequiresNonPublicNestedTypes (); // Warns + type.RequiresAll (); // Warns + } + + static void TestAll ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] Type type) + { + type.RequiresAll (); + type.RequiresNone (); + type.RequiresPublicParameterlessConstructor (); + type.RequiresPublicConstructors (); + type.RequiresNonPublicConstructors (); + type.RequiresPublicMethods (); + type.RequiresNonPublicMethods (); + type.RequiresPublicFields (); + type.RequiresNonPublicFields (); + type.RequiresPublicNestedTypes (); + type.RequiresNonPublicNestedTypes (); + type.RequiresPublicProperties (); + type.RequiresNonPublicProperties (); + type.RequiresPublicEvents (); + type.RequiresNonPublicEvents (); + type.RequiresInterfaces (); + } + + static void RequiresMultiplePrivates ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) + { + } + + static void RequiresSomePublic ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicNestedTypes | DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + + [ExpectedWarning ("IL2067", + nameof (RequiresMultiplePrivates), + nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicMethods), + nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicFields))] + [ExpectedWarning ("IL2067", + nameof (RequiresSomePublic), + nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.Interfaces), + nameof (DynamicallyAccessedMemberTypes) + "." + nameof (DynamicallyAccessedMemberTypes.NonPublicNestedTypes))] + static void TestMultiple ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + RequiresMultiplePrivates (type); + RequiresSomePublic (type); + } + + class TestType { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/TypeInfoAsTypeDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/TypeInfoAsTypeDataFlow.cs new file mode 100644 index 0000000000000..d14b101a9285c --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/TypeInfoAsTypeDataFlow.cs @@ -0,0 +1,55 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class TypeInfoAsTypeDataFlow + { + public static void Main () + { + TestNoAnnotations (typeof (TestType).GetTypeInfo ()); + TestWithAnnotations (typeof (TestType).GetTypeInfo ()); + TestWithNull (); + TestWithNoValue (); + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestNoAnnotations (TypeInfo t) + { + t.AsType ().RequiresPublicMethods (); + t.AsType ().RequiresNone (); + } + + [ExpectedWarning ("IL2067", nameof (DataFlowTypeExtensions.RequiresPublicFields))] + static void TestWithAnnotations ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TypeInfo t) + { + t.AsType ().RequiresPublicMethods (); + t.AsType ().RequiresPublicFields (); + t.AsType ().RequiresNone (); + } + + static void TestWithNull () + { + TypeInfo t = null; + t.AsType ().RequiresPublicMethods (); + } + + static void TestWithNoValue () + { + Type t = null; + Type noValueType = Type.GetTypeFromHandle (t.TypeHandle); + TypeInfo noValue = noValueType.GetTypeInfo (); + noValue.AsType ().RequiresPublicMethods (); + } + + class TestType { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/UnsafeDataFlow.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/UnsafeDataFlow.cs new file mode 100644 index 0000000000000..c4d9f98d58493 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/UnsafeDataFlow.cs @@ -0,0 +1,68 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SetupCompileArgument ("/unsafe")] + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + class UnsafeDataFlow + { + public static void Main () + { + TestReadFromPointer (); + TestWriteToPointer (); + TestWriteToStackAllocedStruct (); + } + + // We don't analyze the pointer manipulation, so it should produce a warning + // about reading an unknown type, without crashing the analyzer. + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] + static unsafe void TestReadFromPointer () + { + int i = 6; + int* pI = &i; + Type[] arr = new Type[] { GetWithPublicMethods () }; + arr[*pI].RequiresAll (); + } + + // We don't analyze the pointer manipulation, so it should produce a warning + // about reading an unknown type, without crashing the analyzer. + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] + static unsafe void TestWriteToPointer () + { + int i = 6; + int* pI = &i; + *pI = 0; + Type[] arr = new Type[] { GetWithPublicMethods () }; + arr[i].RequiresAll (); + } + + // We don't analyze the stackalloc'd struct member, so it should produce a warning + // about reading an unknown type, without crashing the analyzer. + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] + static unsafe void TestWriteToStackAllocedStruct () + { + var stackArr = stackalloc S[1]; + stackArr[0] = new S { + I = 0 + }; + Type[] arr = new Type[] { GetWithPublicMethods () }; + arr[stackArr[0].I].RequiresAll (); + } + + struct S + { + public int I; + } + + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static Type GetWithPublicMethods () => null; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj new file mode 100644 index 0000000000000..ec237817f2901 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj @@ -0,0 +1,17 @@ + + + + $(NetCoreAppToolCurrent) + x64;x86 + AnyCPU + true + $(DefineConstants);INCLUDE_EXPECTATIONS + 0 + 0 + + + + + + + diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Repro/Program.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Repro/Program.cs new file mode 100644 index 0000000000000..6aba1d869f9c1 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Repro/Program.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Repro +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class Program + { + + public static void Main () + { + Console.WriteLine ("HelloWorld"); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs new file mode 100644 index 0000000000000..b89dfc61e8cf3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs @@ -0,0 +1,215 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.RequiresCapability +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class BasicRequires + { + + public static void Main () + { + TestRequiresWithMessageOnlyOnMethod (); + TestRequiresWithMessageAndUrlOnMethod (); + TestRequiresOnConstructor (); + TestRequiresOnPropertyGetterAndSetter (); + TestThatTrailingPeriodIsAddedToMessage (); + TestThatTrailingPeriodIsNotDuplicatedInWarningMessage (); + TestRequiresFromNameOf (); + OnEventMethod.Test (); + RequiresOnGenerics.Test (); + } + + [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageOnly--.")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageOnly--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageOnly--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestRequiresWithMessageOnlyOnMethod () + { + RequiresWithMessageOnly (); + } + + [RequiresUnreferencedCode ("Message for --RequiresWithMessageOnly--")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageOnly--")] + [RequiresDynamicCode ("Message for --RequiresWithMessageOnly--")] + static void RequiresWithMessageOnly () + { + } + + [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestRequiresWithMessageAndUrlOnMethod () + { + RequiresWithMessageAndUrl (); + } + + [RequiresUnreferencedCode ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] + [RequiresDynamicCode ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] + static void RequiresWithMessageAndUrl () + { + } + + [ExpectedWarning ("IL2026", "Message for --ConstructorRequires--.")] + [ExpectedWarning ("IL3002", "Message for --ConstructorRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Message for --ConstructorRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestRequiresOnConstructor () + { + new ConstructorRequires (); + } + + class ConstructorRequires + { + [RequiresUnreferencedCode ("Message for --ConstructorRequires--")] + [RequiresAssemblyFiles ("Message for --ConstructorRequires--")] + [RequiresDynamicCode ("Message for --ConstructorRequires--")] + public ConstructorRequires () + { + } + } + + [ExpectedWarning ("IL2026", "Message for --getter PropertyRequires--.")] + [ExpectedWarning ("IL2026", "Message for --setter PropertyRequires--.")] + [ExpectedWarning ("IL3002", "Message for --getter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3002", "Message for --setter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Message for --getter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Message for --setter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestRequiresOnPropertyGetterAndSetter () + { + _ = PropertyRequires; + PropertyRequires = 0; + } + + static int PropertyRequires { + [RequiresUnreferencedCode ("Message for --getter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --getter PropertyRequires--")] + [RequiresDynamicCode ("Message for --getter PropertyRequires--")] + get { return 42; } + + [RequiresUnreferencedCode ("Message for --setter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --setter PropertyRequires--")] + [RequiresDynamicCode ("Message for --setter PropertyRequires--")] + set { } + } + + [RequiresUnreferencedCode ("Linker adds a trailing period to this message")] + [RequiresAssemblyFiles ("Linker adds a trailing period to this message")] + [RequiresDynamicCode ("Linker adds a trailing period to this message")] + static void WarningMessageWithoutEndingPeriod () + { + } + + [ExpectedWarning ("IL2026", "Linker adds a trailing period to this message.")] + [ExpectedWarning ("IL3002", "Linker adds a trailing period to this message.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Linker adds a trailing period to this message.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestThatTrailingPeriodIsAddedToMessage () + { + WarningMessageWithoutEndingPeriod (); + } + + [RequiresUnreferencedCode ("Linker does not add a period to this message.")] + [RequiresAssemblyFiles ("Linker does not add a period to this message.")] + [RequiresDynamicCode ("Linker does not add a period to this message.")] + static void WarningMessageEndsWithPeriod () + { + } + + [LogDoesNotContain ("Linker does not add a period to this message..")] + [ExpectedWarning ("IL2026", "Linker does not add a period to this message.")] + [ExpectedWarning ("IL3002", "Linker does not add a period to this message.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "Linker does not add a period to this message.", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + static void TestThatTrailingPeriodIsNotDuplicatedInWarningMessage () + { + WarningMessageEndsWithPeriod (); + } + + static void TestRequiresFromNameOf () + { + _ = nameof (BasicRequires.RequiresWithMessageOnly); + } + + class OnEventMethod + { + [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Trimmer)] + static event EventHandler EventToTestRemove { + add { } + [RequiresUnreferencedCode ("Message for --EventToTestRemove.remove--")] + [RequiresAssemblyFiles ("Message for --EventToTestRemove.remove--")] + [RequiresDynamicCode ("Message for --EventToTestRemove.remove--")] + remove { } + } + + [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Trimmer)] + static event EventHandler EventToTestAdd { + [RequiresUnreferencedCode ("Message for --EventToTestAdd.add--")] + [RequiresAssemblyFiles ("Message for --EventToTestAdd.add--")] + [RequiresDynamicCode ("Message for --EventToTestAdd.add--")] + add { } + remove { } + } + + [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--")] + [ExpectedWarning ("IL3002", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL2026", "--EventToTestAdd.add--")] + [ExpectedWarning ("IL3002", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public static void Test () + { + EventToTestRemove -= (sender, e) => { }; + EventToTestAdd += (sender, e) => { }; + } + } + + class RequiresOnGenerics + { + class GenericWithStaticMethod + { + [RequiresUnreferencedCode ("Message for --GenericTypeWithStaticMethodWhichRequires--")] + [RequiresAssemblyFiles ("Message for --GenericTypeWithStaticMethodWhichRequires--")] + [RequiresDynamicCode ("Message for --GenericTypeWithStaticMethodWhichRequires--")] + public static void GenericTypeWithStaticMethodWhichRequires () { } + } + + // NativeAOT doesnt produce Requires warnings in Generics https://github.com/dotnet/runtime/issues/68688 + // [ExpectedWarning("IL2026", "--GenericTypeWithStaticMethodWhichRequires--"] + [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.Trimmer)] + // [ExpectedWarning("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)] + // [ExpectedWarning("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)] + public static void GenericTypeWithStaticMethodViaLdftn () + { + var _ = new Action (GenericWithStaticMethod.GenericTypeWithStaticMethodWhichRequires); + } + + class TestType { } + + static T MakeNew () where T : new() => new T (); + static T MakeNew2 () where T : new() => MakeNew (); + + public static void Test () + { + GenericTypeWithStaticMethodViaLdftn (); + MakeNew2 (); + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs new file mode 100644 index 0000000000000..afcefb9380488 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/CecilExtensions.cs @@ -0,0 +1,368 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Mono.Cecil; + +namespace Mono.Linker.Tests.Extensions +{ + public static class CecilExtensions + { + public static IEnumerable AllDefinedTypes (this AssemblyDefinition assemblyDefinition) + { + return assemblyDefinition.Modules.SelectMany (m => m.AllDefinedTypes ()); + } + + public static IEnumerable AllDefinedTypes (this ModuleDefinition moduleDefinition) + { + foreach (var typeDefinition in moduleDefinition.Types) { + yield return typeDefinition; + + foreach (var definition in typeDefinition.AllDefinedTypes ()) + yield return definition; + } + } + + public static IEnumerable AllDefinedTypes (this TypeDefinition typeDefinition) + { + foreach (var nestedType in typeDefinition.NestedTypes) { + yield return nestedType; + + foreach (var definition in nestedType.AllDefinedTypes ()) + yield return definition; + } + } + + public static IEnumerable AllMembers (this ModuleDefinition module) + { + foreach (var type in module.AllDefinedTypes ()) { + yield return type; + + foreach (var member in type.AllMembers ()) + yield return member; + } + } + + public static IEnumerable AllMembers (this TypeDefinition type) + { + foreach (var field in type.Fields) + yield return field; + + foreach (var prop in type.Properties) + yield return prop; + + foreach (var method in type.Methods) + yield return method; + + foreach (var @event in type.Events) + yield return @event; + } + + public static IEnumerable AllMethods (this TypeDefinition type) + { + foreach (var m in type.AllMembers ()) { + switch (m) { + case MethodDefinition method: + yield return method; + break; + case PropertyDefinition @property: + if (@property.GetMethod != null) + yield return @property.GetMethod; + + if (@property.SetMethod != null) + yield return @property.SetMethod; + + break; + case EventDefinition @event: + if (@event.AddMethod != null) + yield return @event.AddMethod; + + if (@event.RemoveMethod != null) + yield return @event.RemoveMethod; + + break; + + default: + break; + } + } + } + + public static bool HasAttribute (this ICustomAttributeProvider provider, string name) + { + return provider.CustomAttributes.Any (ca => ca.AttributeType.Name == name); + } + + public static bool HasAttributeDerivedFrom (this ICustomAttributeProvider provider, string name) + { + return provider.CustomAttributes.Any (ca => ca.AttributeType.Resolve ().DerivesFrom (name)); + } + + public static bool DerivesFrom (this TypeDefinition type, string baseTypeName) + { + if (type.Name == baseTypeName) + return true; + + if (type.BaseType == null) + return false; + + if (type.BaseType.Name == baseTypeName) + return true; + + return type.BaseType.Resolve ()?.DerivesFrom (baseTypeName) ?? false; + } + + public static PropertyDefinition GetPropertyDefinition (this MethodDefinition method) + { + if (!method.IsSetter && !method.IsGetter) + throw new ArgumentException (); + + var propertyName = method.Name.Substring (4); + return method.DeclaringType.Properties.First (p => p.Name == propertyName); + } + + public static string GetSignature (this MethodDefinition method) + { + var builder = new StringBuilder (); + builder.Append (method.Name); + if (method.HasGenericParameters) { + builder.Append ($"<#{method.GenericParameters.Count}>"); + } + + builder.Append ("("); + + if (method.HasParameters) { + for (int i = 0; i < method.Parameters.Count - 1; i++) { + // TODO: modifiers + // TODO: default values + builder.Append ($"{method.Parameters[i].ParameterType},"); + } + + builder.Append (method.Parameters[method.Parameters.Count - 1].ParameterType); + } + + builder.Append (")"); + + return builder.ToString (); + } + + public static object GetConstructorArgumentValue (this CustomAttribute attr, int argumentIndex) + { + return attr.ConstructorArguments[argumentIndex].Value; + } + + public static object? GetPropertyValue (this CustomAttribute attr, string propertyName) + { + foreach (var prop in attr.Properties) + if (prop.Name == propertyName) + return prop.Argument.Value; + + return null; + } + + public static bool IsEventMethod(this MethodDefinition md) + { + return (md.SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0 || + (md.SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0 || + (md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0; + } + + public static string GetDisplayName(this MethodReference method) + { + var sb = new System.Text.StringBuilder(); + + // Match C# syntaxis name if setter or getter + var methodDefinition = method.Resolve(); + if (methodDefinition != null && (methodDefinition.IsSetter || methodDefinition.IsGetter)) + { + // Append property name + string name = methodDefinition.IsSetter ? string.Concat(methodDefinition.Name.AsSpan(4), ".set") : string.Concat(methodDefinition.Name.AsSpan(4), ".get"); + sb.Append(name); + // Insert declaring type name and namespace + sb.Insert(0, '.').Insert(0, method.DeclaringType?.GetDisplayName()); + return sb.ToString(); + } + + if (methodDefinition != null && methodDefinition.IsEventMethod()) + { + // Append event name + string name = methodDefinition.SemanticsAttributes switch + { + MethodSemanticsAttributes.AddOn => string.Concat(methodDefinition.Name.AsSpan(4), ".add"), + MethodSemanticsAttributes.RemoveOn => string.Concat(methodDefinition.Name.AsSpan(7), ".remove"), + MethodSemanticsAttributes.Fire => string.Concat(methodDefinition.Name.AsSpan(6), ".raise"), + _ => throw new NotSupportedException(), + }; + sb.Append(name); + // Insert declaring type name and namespace + sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); + return sb.ToString(); + } + + // Append parameters + sb.Append("("); + if (method.HasParameters) + { + for (int i = 0; i < method.Parameters.Count - 1; i++) + sb.Append(method.Parameters[i].ParameterType.GetDisplayNameWithoutNamespace()).Append(", "); + + sb.Append(method.Parameters[method.Parameters.Count - 1].ParameterType.GetDisplayNameWithoutNamespace()); + } + + sb.Append(")"); + + // Insert generic parameters + if (method.HasGenericParameters) + { + PrependGenericParameters(method.GenericParameters, sb); + } + + // Insert method name + if (method.Name == ".ctor") + sb.Insert(0, method.DeclaringType.Name); + else + sb.Insert(0, method.Name); + + // Insert declaring type name and namespace + if (method.DeclaringType != null) + sb.Insert(0, '.').Insert(0, method.DeclaringType.GetDisplayName()); + + return sb.ToString(); + } + + public static string GetDisplayName(this TypeReference type) + { + var builder = GetDisplayNameWithoutNamespace(type); + var namespaceDisplayName = type.GetNamespaceDisplayName(); + if (!string.IsNullOrEmpty(namespaceDisplayName)) + { + builder.Insert(0, "."); + builder.Insert(0, namespaceDisplayName); + } + + return builder.ToString(); + } + + public static string GetDisplayName(this FieldReference field) + { + var builder = new StringBuilder(); + if (field.DeclaringType != null) + { + builder.Append(field.DeclaringType.GetDisplayName()); + builder.Append("."); + } + + builder.Append(field.Name); + + return builder.ToString(); + } + + public static string GetNamespaceDisplayName(this MemberReference member) + { + var type = member is TypeReference typeReference ? typeReference : member.DeclaringType; + while (type.DeclaringType != null) + type = type.DeclaringType; + + return type.Namespace; + } + + public static StringBuilder GetDisplayNameWithoutNamespace(this TypeReference type) + { + var sb = new StringBuilder(); + if (type == null) + return sb; + + Stack? genericArguments = null; + while (true) + { + switch (type) + { + case ArrayType arrayType: + AppendArrayType(arrayType, sb); + break; + case GenericInstanceType genericInstanceType: + genericArguments = new Stack(genericInstanceType.GenericArguments); + type = genericInstanceType.ElementType; + continue; + default: + if (type.HasGenericParameters) + { + int genericParametersCount = type.GenericParameters.Count; + int declaringTypeGenericParametersCount = type.DeclaringType?.GenericParameters?.Count ?? 0; + + string simpleName; + if (genericParametersCount > declaringTypeGenericParametersCount) + { + if (genericArguments?.Count > 0) + PrependGenericArguments(genericArguments, genericParametersCount - declaringTypeGenericParametersCount, sb); + else + PrependGenericParameters(type.GenericParameters.Skip(declaringTypeGenericParametersCount).ToList(), sb); + + int explicitArityIndex = type.Name.IndexOf('`'); + simpleName = explicitArityIndex != -1 ? type.Name.Substring(0, explicitArityIndex) : type.Name; + } + else + simpleName = type.Name; + + sb.Insert(0, simpleName); + break; + } + + sb.Insert(0, type.Name); + break; + } + + if (type.DeclaringType is not TypeReference declaringType) + break; + + type = declaringType; + + sb.Insert(0, '.'); + } + + return sb; + } + + public static void PrependGenericParameters(IList genericParameters, StringBuilder sb) + { + sb.Insert(0, '>').Insert(0, genericParameters[genericParameters.Count - 1]); + for (int i = genericParameters.Count - 2; i >= 0; i--) + sb.Insert(0, ',').Insert(0, genericParameters[i]); + + sb.Insert(0, '<'); + } + + static void PrependGenericArguments(Stack genericArguments, int argumentsToTake, StringBuilder sb) + { + sb.Insert(0, '>').Insert(0, genericArguments.Pop().GetDisplayNameWithoutNamespace().ToString()); + while (--argumentsToTake > 0) + sb.Insert(0, ',').Insert(0, genericArguments.Pop().GetDisplayNameWithoutNamespace().ToString()); + + sb.Insert(0, '<'); + } + + static void AppendArrayType(ArrayType arrayType, StringBuilder sb) + { + void parseArrayDimensions(ArrayType at) + { + sb.Append('['); + for (int i = 0; i < at.Dimensions.Count - 1; i++) + sb.Append(','); + + sb.Append(']'); + } + + sb.Append(arrayType.Name.AsSpan(0, arrayType.Name.IndexOf('['))); + parseArrayDimensions(arrayType); + var element = arrayType.ElementType as ArrayType; + while (element != null) + { + parseArrayDimensions(element); + element = element.ElementType as ArrayType; + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs new file mode 100644 index 0000000000000..9272ffc026c03 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs @@ -0,0 +1,864 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// The MIT License(MIT) +// ===================== +// +// Copyright © `2015-2017` `Lucas Meijer` +// +// 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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Mono.Linker.Tests.Extensions +{ + public class NPath : IEquatable, IComparable + { + private static readonly StringComparison PathStringComparison = IsLinux () ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; + + private readonly string[] _elements; + private readonly bool _isRelative; + private readonly string? _driveLetter; + + #region construction + + public NPath (string path) + { + if (path == null) + throw new ArgumentNullException (); + + path = ParseDriveLetter (path, out _driveLetter); + + if (path == "/") { + _isRelative = false; + _elements = new string[] { }; + } else { + var split = path.Split ('/', '\\'); + + _isRelative = _driveLetter == null && IsRelativeFromSplitString (split); + + _elements = ParseSplitStringIntoElements (split.Where (s => s.Length > 0).ToArray ()); + } + } + + private NPath (string[] elements, bool isRelative, string? driveLetter) + { + _elements = elements; + _isRelative = isRelative; + _driveLetter = driveLetter; + } + + private string[] ParseSplitStringIntoElements (IEnumerable inputs) + { + var stack = new List (); + + foreach (var input in inputs.Where (input => input.Length != 0)) { + if (input == ".") { + if ((stack.Count > 0) && (stack.Last () != ".")) + continue; + } else if (input == "..") { + if (HasNonDotDotLastElement (stack)) { + stack.RemoveAt (stack.Count - 1); + continue; + } + if (!_isRelative) + throw new ArgumentException ("You cannot create a path that tries to .. past the root"); + } + stack.Add (input); + } + return stack.ToArray (); + } + + private static bool HasNonDotDotLastElement (List stack) + { + return stack.Count > 0 && stack[stack.Count - 1] != ".."; + } + + private string ParseDriveLetter (string path, out string? driveLetter) + { + if (path.Length >= 2 && path[1] == ':') { + driveLetter = path[0].ToString (); + return path.Substring (2); + } + + driveLetter = null; + return path; + } + + private static bool IsRelativeFromSplitString (string[] split) + { + if (split.Length < 2) + return true; + + return split[0].Length != 0 || !split.Any (s => s.Length > 0); + } + + public NPath Combine (params string[] append) + { + return Combine (append.Select (a => new NPath (a)).ToArray ()); + } + + public NPath Combine (params NPath[] append) + { + if (!append.All (p => p.IsRelative)) + throw new ArgumentException ("You cannot .Combine a non-relative path"); + + return new NPath (ParseSplitStringIntoElements (_elements.Concat (append.SelectMany (p => p._elements))), _isRelative, _driveLetter); + } + + public NPath Parent { + get { + if (_elements.Length == 0) + throw new InvalidOperationException ("Parent is called on an empty path"); + + var newElements = _elements.Take (_elements.Length - 1).ToArray (); + + return new NPath (newElements, _isRelative, _driveLetter); + } + } + + public NPath RelativeTo (NPath path) + { + if (!IsChildOf (path)) { + if (!IsRelative && !path.IsRelative && _driveLetter != path._driveLetter) + throw new ArgumentException ("Path.RelativeTo() was invoked with two paths that are on different volumes. invoked on: " + ToString () + " asked to be made relative to: " + path); + + NPath? commonParent = null; + foreach (var parent in RecursiveParents) { + commonParent = path.RecursiveParents.FirstOrDefault (otherParent => otherParent == parent); + + if (commonParent != null) + break; + } + + if (commonParent == null) + throw new ArgumentException ("Path.RelativeTo() was unable to find a common parent between " + ToString () + " and " + path); + + if (IsRelative && path.IsRelative && commonParent.IsEmpty ()) + throw new ArgumentException ("Path.RelativeTo() was invoked with two relative paths that do not share a common parent. Invoked on: " + ToString () + " asked to be made relative to: " + path); + + var depthDiff = path.Depth - commonParent.Depth; + return new NPath (Enumerable.Repeat ("..", depthDiff).Concat (_elements.Skip (commonParent.Depth)).ToArray (), true, null); + } + + return new NPath (_elements.Skip (path._elements.Length).ToArray (), true, null); + } + + public NPath ChangeExtension (string extension) + { + ThrowIfRoot (); + + var newElements = (string[]) _elements.Clone (); + newElements[newElements.Length - 1] = Path.ChangeExtension (_elements[_elements.Length - 1], WithDot (extension)); + if (extension == string.Empty) + newElements[newElements.Length - 1] = newElements[newElements.Length - 1].TrimEnd ('.'); + return new NPath (newElements, _isRelative, _driveLetter); + } + #endregion construction + + #region inspection + + public bool IsRelative { + get { return _isRelative; } + } + + public string FileName { + get { + ThrowIfRoot (); + + return _elements.Last (); + } + } + + public string FileNameWithoutExtension { + get { return Path.GetFileNameWithoutExtension (FileName); } + } + + public IEnumerable Elements { + get { return _elements; } + } + + public int Depth { + get { return _elements.Length; } + } + + public bool Exists (string append = "") + { + return Exists (new NPath (append)); + } + + public bool Exists (NPath append) + { + return FileExists (append) || DirectoryExists (append); + } + + public bool DirectoryExists (string append = "") + { + return DirectoryExists (new NPath (append)); + } + + public bool DirectoryExists (NPath append) + { + return Directory.Exists (Combine (append).ToString ()); + } + + public bool FileExists (string append = "") + { + return FileExists (new NPath (append)); + } + + public bool FileExists (NPath append) + { + return File.Exists (Combine (append).ToString ()); + } + + public string ExtensionWithDot { + get { + if (IsRoot) + throw new ArgumentException ("A root directory does not have an extension"); + + var last = _elements.Last (); + var index = last.LastIndexOf ("."); + if (index < 0) return String.Empty; + return last.Substring (index); + } + } + + public string InQuotes () + { + return "\"" + ToString () + "\""; + } + + public string InQuotes (SlashMode slashMode) + { + return "\"" + ToString (slashMode) + "\""; + } + + public override string ToString () + { + return ToString (SlashMode.Native); + } + + public string ToString (SlashMode slashMode) + { + // Check if it's linux root / + if (IsRoot && string.IsNullOrEmpty (_driveLetter)) + return Slash (slashMode).ToString (); + + if (_isRelative && _elements.Length == 0) + return "."; + + var sb = new StringBuilder (); + if (_driveLetter != null) { + sb.Append (_driveLetter); + sb.Append (":"); + } + if (!_isRelative) + sb.Append (Slash (slashMode)); + var first = true; + foreach (var element in _elements) { + if (!first) + sb.Append (Slash (slashMode)); + + sb.Append (element); + first = false; + } + return sb.ToString (); + } + + public static implicit operator string (NPath path) + { + return path.ToString (); + } + + static char Slash (SlashMode slashMode) + { + return slashMode switch { + SlashMode.Backward => '\\', + SlashMode.Forward => '/', + _ => Path.DirectorySeparatorChar, + }; + } + + public override bool Equals (Object? obj) + { + if (obj == null) + return false; + + // If parameter cannot be cast to Point return false. + if (!(obj is NPath p)) + return false; + + return Equals (p); + } + + public bool Equals (NPath? p) + { + if (p == null) + return false; + + if (p._isRelative != _isRelative) + return false; + + if (!string.Equals (p._driveLetter, _driveLetter, PathStringComparison)) + return false; + + if (p._elements.Length != _elements.Length) + return false; + + for (var i = 0; i != _elements.Length; i++) + if (!string.Equals (p._elements[i], _elements[i], PathStringComparison)) + return false; + + return true; + } + + public static bool operator == (NPath? a, NPath? b) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals (a, b)) + return true; + + // If one is null, but not both, return false. + if ((a is null) || (b is null)) + return false; + + // Return true if the fields match: + return a.Equals (b); + } + + public override int GetHashCode () + { + unchecked { + int hash = 17; + // Suitable nullity checks etc, of course :) + hash = hash * 23 + _isRelative.GetHashCode (); + foreach (var element in _elements) + hash = hash * 23 + element.GetHashCode (); + if (_driveLetter != null) + hash = hash * 23 + _driveLetter.GetHashCode (); + return hash; + } + } + + public int CompareTo (object? obj) + { + if (obj == null) + return -1; + + return this.ToString ().CompareTo (((NPath) obj).ToString ()); + } + + public static bool operator != (NPath? a, NPath? b) + { + return !(a == b); + } + + public bool HasExtension (params string[] extensions) + { + var extensionWithDotLower = ExtensionWithDot.ToLower (); + return extensions.Any (e => WithDot (e).ToLower () == extensionWithDotLower); + } + + private static string WithDot (string extension) + { + return extension.StartsWith (".") ? extension : "." + extension; + } + + private bool IsEmpty () + { + return _elements.Length == 0; + } + + public bool IsRoot { + get { return _elements.Length == 0 && !_isRelative; } + } + + #endregion inspection + + #region directory enumeration + + public IEnumerable Files (string filter, bool recurse = false) + { + return Directory.GetFiles (ToString (), filter, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Select (s => new NPath (s)); + } + + public IEnumerable Files (bool recurse = false) + { + return Files ("*", recurse); + } + + public IEnumerable Contents (string filter, bool recurse = false) + { + return Files (filter, recurse).Concat (Directories (filter, recurse)); + } + + public IEnumerable Contents (bool recurse = false) + { + return Contents ("*", recurse); + } + + public IEnumerable Directories (string filter, bool recurse = false) + { + return Directory.GetDirectories (ToString (), filter, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Select (s => new NPath (s)); + } + + public IEnumerable Directories (bool recurse = false) + { + return Directories ("*", recurse); + } + + #endregion + + #region filesystem writing operations + public NPath CreateFile () + { + ThrowIfRelative (); + ThrowIfRoot (); + EnsureParentDirectoryExists (); + File.WriteAllBytes (ToString (), new byte[0]); + return this; + } + + public NPath CreateFile (string file) + { + return CreateFile (new NPath (file)); + } + + public NPath CreateFile (NPath file) + { + if (!file.IsRelative) + throw new ArgumentException ("You cannot call CreateFile() on an existing path with a non relative argument"); + return Combine (file).CreateFile (); + } + + public NPath CreateDirectory () + { + ThrowIfRelative (); + + if (IsRoot) + throw new NotSupportedException ("CreateDirectory is not supported on a root level directory because it would be dangerous:" + ToString ()); + + Directory.CreateDirectory (ToString ()); + return this; + } + + public NPath CreateDirectory (string directory) + { + return CreateDirectory (new NPath (directory)); + } + + public NPath CreateDirectory (NPath directory) + { + if (!directory.IsRelative) + throw new ArgumentException ("Cannot call CreateDirectory with an absolute argument"); + + return Combine (directory).CreateDirectory (); + } + + public NPath? Copy (string dest) + { + return Copy (new NPath (dest)); + } + + public NPath? Copy (string dest, Func fileFilter) + { + return Copy (new NPath (dest), fileFilter); + } + + public NPath? Copy (NPath dest) + { + return Copy (dest, p => true); + } + + public NPath? Copy (NPath dest, Func fileFilter) + { + ThrowIfRelative (); + if (dest.IsRelative) + dest = Parent.Combine (dest); + + if (dest.DirectoryExists ()) + return CopyWithDeterminedDestination (dest.Combine (FileName), fileFilter); + + return CopyWithDeterminedDestination (dest, fileFilter); + } + + public NPath MakeAbsolute () + { + if (!IsRelative) + return this; + + return NPath.CurrentDirectory.Combine (this); + } + + NPath? CopyWithDeterminedDestination (NPath absoluteDestination, Func fileFilter) + { + if (absoluteDestination.IsRelative) + throw new ArgumentException ("absoluteDestination must be absolute"); + + if (FileExists ()) { + if (!fileFilter (absoluteDestination)) + return null; + + absoluteDestination.EnsureParentDirectoryExists (); + + File.Copy (ToString (), absoluteDestination.ToString (), true); + return absoluteDestination; + } + + if (DirectoryExists ()) { + absoluteDestination.EnsureDirectoryExists (); + foreach (var thing in Contents ()) + thing.CopyWithDeterminedDestination (absoluteDestination.Combine (thing.RelativeTo (this)), fileFilter); + return absoluteDestination; + } + + throw new ArgumentException ("Copy() called on path that doesnt exist: " + ToString ()); + } + + public void Delete (DeleteMode deleteMode = DeleteMode.Normal) + { + ThrowIfRelative (); + + if (IsRoot) + throw new NotSupportedException ("Delete is not supported on a root level directory because it would be dangerous:" + ToString ()); + + if (FileExists ()) + File.Delete (ToString ()); + else if (DirectoryExists ()) + try { + Directory.Delete (ToString (), true); + } catch (IOException) { + if (deleteMode == DeleteMode.Normal) + throw; + } + else + throw new InvalidOperationException ("Trying to delete a path that does not exist: " + ToString ()); + } + + public void DeleteIfExists (DeleteMode deleteMode = DeleteMode.Normal) + { + ThrowIfRelative (); + + if (FileExists () || DirectoryExists ()) + Delete (deleteMode); + } + + public NPath DeleteContents () + { + ThrowIfRelative (); + + if (IsRoot) + throw new NotSupportedException ("DeleteContents is not supported on a root level directory because it would be dangerous:" + ToString ()); + + if (FileExists ()) + throw new InvalidOperationException ("It is not valid to perform this operation on a file"); + + if (DirectoryExists ()) { + try { + Files ().Delete (); + Directories ().Delete (); + } catch (IOException) { + if (Files (true).Any ()) + throw; + } + + return this; + } + + return EnsureDirectoryExists (); + } + + public static NPath CreateTempDirectory (string myprefix) + { + var random = new Random (); + while (true) { + var candidate = new NPath (Path.GetTempPath () + "/" + myprefix + "_" + random.Next ()); + if (!candidate.Exists ()) + return candidate.CreateDirectory (); + } + } + + public NPath Move (string dest) + { + return Move (new NPath (dest)); + } + + public NPath Move (NPath dest) + { + ThrowIfRelative (); + + if (IsRoot) + throw new NotSupportedException ("Move is not supported on a root level directory because it would be dangerous:" + ToString ()); + + if (dest.IsRelative) + return Move (Parent.Combine (dest)); + + if (dest.DirectoryExists ()) + return Move (dest.Combine (FileName)); + + if (FileExists ()) { + dest.EnsureParentDirectoryExists (); + File.Move (ToString (), dest.ToString ()); + return dest; + } + + if (DirectoryExists ()) { + Directory.Move (ToString (), dest.ToString ()); + return dest; + } + + throw new ArgumentException ("Move() called on a path that doesn't exist: " + ToString ()); + } + + #endregion + + #region special paths + + public static NPath CurrentDirectory { + get { + return new NPath (Directory.GetCurrentDirectory ()); + } + } + + public static NPath HomeDirectory { + get { + if (Path.DirectorySeparatorChar == '\\') + return new NPath (Environment.GetEnvironmentVariable ("USERPROFILE")!); + return new NPath (Environment.GetEnvironmentVariable ("HOME")!); + } + } + + public static NPath SystemTemp { + get { + return new NPath (Path.GetTempPath ()); + } + } + + #endregion + + private void ThrowIfRelative () + { + if (_isRelative) + throw new ArgumentException ("You are attempting an operation on a Path that requires an absolute path, but the path is relative"); + } + + private void ThrowIfRoot () + { + if (IsRoot) + throw new ArgumentException ("You are attempting an operation that is not valid on a root level directory"); + } + + public NPath EnsureDirectoryExists (string append = "") + { + return EnsureDirectoryExists (new NPath (append)); + } + + public NPath EnsureDirectoryExists (NPath append) + { + var combined = Combine (append); + if (combined.DirectoryExists ()) + return combined; + combined.EnsureParentDirectoryExists (); + combined.CreateDirectory (); + return combined; + } + + public NPath EnsureParentDirectoryExists () + { + var parent = Parent; + parent.EnsureDirectoryExists (); + return parent; + } + + public NPath FileMustExist () + { + if (!FileExists ()) + throw new FileNotFoundException ("File was expected to exist : " + ToString ()); + + return this; + } + + public NPath DirectoryMustExist () + { + if (!DirectoryExists ()) + throw new DirectoryNotFoundException ("Expected directory to exist : " + ToString ()); + + return this; + } + + public bool IsChildOf (string potentialBasePath) + { + return IsChildOf (new NPath (potentialBasePath)); + } + + public bool IsChildOf (NPath potentialBasePath) + { + if ((IsRelative && !potentialBasePath.IsRelative) || !IsRelative && potentialBasePath.IsRelative) + throw new ArgumentException ("You can only call IsChildOf with two relative paths, or with two absolute paths"); + + // If the other path is the root directory, then anything is a child of it as long as it's not a Windows path + if (potentialBasePath.IsRoot) { + if (_driveLetter != potentialBasePath._driveLetter) + return false; + return true; + } + + if (IsEmpty ()) + return false; + + if (Equals (potentialBasePath)) + return true; + + return Parent.IsChildOf (potentialBasePath); + } + + public IEnumerable RecursiveParents { + get { + var candidate = this; + while (true) { + if (candidate.IsEmpty ()) + yield break; + + candidate = candidate.Parent; + yield return candidate; + } + } + } + + public NPath WriteAllText (string contents) + { + ThrowIfRelative (); + EnsureParentDirectoryExists (); + File.WriteAllText (ToString (), contents); + return this; + } + + public string ReadAllText () + { + ThrowIfRelative (); + return File.ReadAllText (ToString ()); + } + + public NPath WriteAllLines (string[] contents) + { + ThrowIfRelative (); + EnsureParentDirectoryExists (); + File.WriteAllLines (ToString (), contents); + return this; + } + + public string[] ReadAllLines () + { + ThrowIfRelative (); + return File.ReadAllLines (ToString ()); + } + + public IEnumerable CopyFiles (NPath destination, bool recurse, Func? fileFilter = null) + { + destination.EnsureDirectoryExists (); + return Files (recurse).Where (fileFilter ?? AlwaysTrue).Select (file => file.Copy (destination.Combine (file.RelativeTo (this)))).ToArray (); + } + + public IEnumerable MoveFiles (NPath destination, bool recurse, Func? fileFilter = null) + { + if (IsRoot) + throw new NotSupportedException ("MoveFiles is not supported on this directory because it would be dangerous:" + ToString ()); + + destination.EnsureDirectoryExists (); + return Files (recurse).Where (fileFilter ?? AlwaysTrue).Select (file => file.Move (destination.Combine (file.RelativeTo (this)))).ToArray (); + } + + static bool AlwaysTrue (NPath p) + { + return true; + } + + private static bool IsLinux () + { + return Directory.Exists ("/proc"); + } + } + + public static class Extensions + { + public static IEnumerable Copy (this IEnumerable self, string dest) + { + return Copy (self, new NPath (dest)); + } + + public static IEnumerable Copy (this IEnumerable self, NPath dest) + { + if (dest.IsRelative) + throw new ArgumentException ("When copying multiple files, the destination cannot be a relative path"); + dest.EnsureDirectoryExists (); + return self.Select (p => p.Copy (dest.Combine (p.FileName))).ToArray (); + } + + public static IEnumerable Move (this IEnumerable self, string dest) + { + return Move (self, new NPath (dest)); + } + + public static IEnumerable Move (this IEnumerable self, NPath dest) + { + if (dest.IsRelative) + throw new ArgumentException ("When moving multiple files, the destination cannot be a relative path"); + dest.EnsureDirectoryExists (); + return self.Select (p => p.Move (dest.Combine (p.FileName))).ToArray (); + } + + public static IEnumerable Delete (this IEnumerable self) + { + foreach (var p in self) + p.Delete (); + return self; + } + + public static IEnumerable InQuotes (this IEnumerable self, SlashMode forward = SlashMode.Native) + { + return self.Select (p => p.InQuotes (forward)); + } + + public static NPath ToNPath (this string path) + { + return new NPath (path); + } + } + + public enum SlashMode + { + Native, + Forward, + Backward + } + + public enum DeleteMode + { + Normal, + Soft + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/Mono.Linker.Tests.csproj b/src/coreclr/tools/aot/Mono.Linker.Tests/Mono.Linker.Tests.csproj new file mode 100644 index 0000000000000..479c971ed03fd --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/Mono.Linker.Tests.csproj @@ -0,0 +1,51 @@ + + + + $(NetCoreAppToolCurrent) + enable + + false + true + x64;x86 + AnyCPU + + linux-x64;win-x64;osx-x64 + Debug;Release;Checked + + + + + + + + + + + + + + + + $(RuntimeBinDir) + + + $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir) + + + $(Configuration) + + + $(ArtifactsDir) + + + $(ArtifactsBinDir) + + + $(_DirectoryBuildPropsBasePath) + + + $(TargetArchitecture) + + + + diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestCase.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestCase.cs new file mode 100644 index 0000000000000..a9c383d52c2d3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestCase.cs @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using Mono.Linker.Tests.Extensions; + +namespace Mono.Linker.Tests.TestCases +{ + public class TestCase + { + public TestCase (NPath sourceFile, NPath rootCasesDirectory, NPath originalTestCaseAssemblyPath) + { + SourceFile = sourceFile; + RootCasesDirectory = rootCasesDirectory; + OriginalTestCaseAssemblyPath = originalTestCaseAssemblyPath; + Name = sourceFile.FileNameWithoutExtension; + var fullyRelative = sourceFile.RelativeTo (rootCasesDirectory); + var displayNameRelative = fullyRelative.RelativeTo (new NPath (fullyRelative.Elements.First ())); + string displayNameBase = displayNameRelative.Depth == 1 ? "" : displayNameRelative.Parent.ToString (SlashMode.Forward).Replace ('/', '.') + "."; + DisplayName = $"{displayNameBase}{sourceFile.FileNameWithoutExtension}"; + + // A little hacky, but good enough for name. No reason why namespace & type names + // should not follow the directory structure + //ReconstructedFullTypeName = $"{sourceFile.Parent.RelativeTo (rootCasesDirectory.Parent).ToString (SlashMode.Forward).Replace ('/', '.')}.{sourceFile.FileNameWithoutExtension}"; + ReconstructedFullTypeName = $"Mono.Linker.Tests.Cases.{fullyRelative.Parent.ToString (SlashMode.Forward).Replace ('/', '.')}.{sourceFile.FileNameWithoutExtension}"; + + var firstParentRelativeToRoot = SourceFile.RelativeTo (rootCasesDirectory).Elements.First (); + TestSuiteDirectory = rootCasesDirectory.Combine (firstParentRelativeToRoot); + } + + public NPath RootCasesDirectory { get; } + + public string Name { get; } + + public string DisplayName { get; } + + public NPath SourceFile { get; } + + public NPath OriginalTestCaseAssemblyPath { get; } + + public string ReconstructedFullTypeName { get; } + + public bool HasLinkXmlFile { + get { return SourceFile.ChangeExtension ("xml").FileExists (); } + } + + public NPath LinkXmlFile { + get { + if (!HasLinkXmlFile) + throw new InvalidOperationException ("This test case does not have a link xml file"); + + return SourceFile.ChangeExtension ("xml"); + } + } + + public NPath TestSuiteDirectory { get; } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs new file mode 100644 index 0000000000000..71c527c459d77 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs @@ -0,0 +1,76 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCasesRunner; + +namespace Mono.Linker.Tests.TestCases +{ + public static class TestDatabase + { + private static TestCase[]? _cachedAllCases; + + public static IEnumerable DataFlow () + { + return TestNamesBySuiteName ("DataFlow"); + } + + public static IEnumerable Repro () + { + return TestNamesBySuiteName ("Repro"); + } + + public static IEnumerable RequiresCapability () + { + return TestNamesBySuiteName ("RequiresCapability"); + } + + public static TestCaseCollector CreateCollector () + { + GetDirectoryPaths (out string rootSourceDirectory, out string testCaseAssemblyPath); + return new TestCaseCollector (rootSourceDirectory, testCaseAssemblyPath); + } + + public static NPath TestCasesRootDirectory { + get { + GetDirectoryPaths (out string rootSourceDirectory, out string _); + return rootSourceDirectory.ToNPath (); + } + } + + static IEnumerable AllCases () + { + if (_cachedAllCases == null) + _cachedAllCases = CreateCollector () + .Collect () + .Where (c => c != null) + .OrderBy (c => c.DisplayName) + .ToArray (); + + return _cachedAllCases; + } + + public static TestCase? GetTestCaseFromName (string name) + { + return AllCases ().FirstOrDefault (c => c.Name == name); + } + + static IEnumerable TestNamesBySuiteName (string suiteName) + { + return AllCases () + .Where (c => c.TestSuiteDirectory.FileName == suiteName) + .Select (c => c.DisplayName) + .OrderBy (c => c) + .Select (c => new object[] { c }); + } + + static void GetDirectoryPaths (out string rootSourceDirectory, out string testCaseAssemblyPath) + { + rootSourceDirectory = Path.GetFullPath (Path.Combine (PathUtilities.GetTestsSourceRootDirectory (), "Mono.Linker.Tests.Cases")); + testCaseAssemblyPath = PathUtilities.GetTestAssemblyPath ("Mono.Linker.Tests.Cases"); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs new file mode 100644 index 0000000000000..00cbb1437c10c --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs @@ -0,0 +1,45 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Mono.Linker.Tests.TestCasesRunner; +using Xunit; + +namespace Mono.Linker.Tests.TestCases +{ + public class All + { + + [Theory] + [MemberData(nameof(TestDatabase.DataFlow), MemberType = typeof(TestDatabase))] + public void DataFlow(string t) + { + Run(t); + } + + [Theory] + [MemberData (nameof (TestDatabase.Repro), MemberType = typeof (TestDatabase))] + public void Repro (string t) + { + Run (t); + } + + [Theory] + [MemberData(nameof(TestDatabase.RequiresCapability), MemberType = typeof(TestDatabase))] + public void RequiresCapability(string t) + { + Run(t); + } + + protected virtual void Run(string testName) + { + TestCase testCase = TestDatabase.GetTestCaseFromName(testName) ?? throw new InvalidOperationException($"Unknown test {testName}"); + var runner = new TestRunner(new ObjectFactory()); + var linkedResult = runner.Run(testCase); + if (linkedResult != null) + { + new ResultChecker().Check(linkedResult); + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs new file mode 100644 index 0000000000000..cac049b732ebb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs @@ -0,0 +1,960 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentAssertions; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Extensions; +using Xunit; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class AssemblyChecker + { + readonly AssemblyDefinition originalAssembly, linkedAssembly; + + HashSet linkedMembers; + readonly HashSet verifiedGeneratedFields = new HashSet (); + readonly HashSet verifiedEventMethods = new HashSet (); + readonly HashSet verifiedGeneratedTypes = new HashSet (); + bool checkNames; + + public AssemblyChecker (AssemblyDefinition original, AssemblyDefinition linked) + { + this.originalAssembly = original; + this.linkedAssembly = linked; + this.linkedMembers = new (StringComparer.Ordinal); + + checkNames = original.MainModule.GetTypeReferences ().Any (attr => + attr.Name == nameof (RemovedNameValueAttribute)); + } + + public void Verify () + { + VerifyExportedTypes (originalAssembly, linkedAssembly); + + VerifyCustomAttributes (originalAssembly, linkedAssembly); + VerifySecurityAttributes (originalAssembly, linkedAssembly); + + foreach (var originalModule in originalAssembly.Modules) + VerifyModule (originalModule, linkedAssembly.Modules.FirstOrDefault (m => m.Name == originalModule.Name)); + + VerifyResources (originalAssembly, linkedAssembly); + VerifyReferences (originalAssembly, linkedAssembly); + + foreach (var s in linkedAssembly.MainModule.AllMembers ().Select (s => s.FullName)) { + this.linkedMembers.Add (s); + } + + var membersToAssert = originalAssembly.MainModule.Types; + foreach (var originalMember in membersToAssert) { + if (originalMember is TypeDefinition td) { + if (td.Name == "") { + linkedMembers.Remove (td.Name); + continue; + } + + TypeDefinition linkedType = linkedAssembly.MainModule.GetType (originalMember.FullName); + VerifyTypeDefinition (td, linkedType); + linkedMembers.Remove (td.FullName); + + continue; + } + + throw new NotImplementedException ($"Don't know how to check member of type {originalMember.GetType ()}"); + } + + Assert.Empty (linkedMembers); + } + + protected virtual void VerifyModule (ModuleDefinition original, ModuleDefinition? linked) + { + // We never link away a module today so let's make sure the linked one isn't null + if (linked == null) { + Assert.True (false, $"Linked assembly `{original.Assembly.Name.Name}` is missing module `{original.Name}`"); + return; + } + + var expected = original.Assembly.MainModule.AllDefinedTypes () + .SelectMany (t => GetCustomAttributeCtorValues (t, nameof (KeptModuleReferenceAttribute))) + .ToArray (); + + var actual = linked.ModuleReferences + .Select (name => name.Name) + .ToArray (); + + Assert.Equal (expected, actual); + + VerifyCustomAttributes (original, linked); + } + + protected virtual void VerifyTypeDefinition (TypeDefinition original, TypeDefinition? linked) + { + if (linked != null && verifiedGeneratedTypes.Contains (linked.FullName)) + return; + + ModuleDefinition? linkedModule = linked?.Module; + + // + // Little bit complex check to allow easier test writing to match + // - It has [Kept] attribute or any variation of it + // - It contains Main method + // - It contains at least one member which has [Kept] attribute (not recursive) + // + bool expectedKept = + original.HasAttributeDerivedFrom (nameof (KeptAttribute)) || + (linked != null && linkedModule!.Assembly.EntryPoint?.DeclaringType == linked) || + original.AllMembers ().Any (l => l.HasAttribute (nameof (KeptAttribute))); + + if (!expectedKept) { + if (linked != null) + Assert.True (false, $"Type `{original}' should have been removed"); + + return; + } + + bool prev = checkNames; + checkNames |= original.HasAttribute (nameof (VerifyMetadataNamesAttribute)); + + VerifyTypeDefinitionKept (original, linked); + + checkNames = prev; + + if (original.HasAttribute (nameof (CreatedMemberAttribute))) { + foreach (var attr in original.CustomAttributes.Where (l => l.AttributeType.Name == nameof (CreatedMemberAttribute))) { + var newName = original.FullName + "::" + attr.ConstructorArguments[0].Value.ToString (); + + if (linkedMembers!.RemoveWhere (l => l.Contains (newName)) != 1) + Assert.True (false, $"Newly created member '{newName}' was not found"); + } + } + } + + protected virtual void VerifyTypeDefinitionKept (TypeDefinition original, TypeDefinition? linked) + { + if (linked == null) { + Assert.True (false, $"Type `{original}' should have been kept"); + return; + } + + if (!original.IsInterface) + VerifyBaseType (original, linked); + + VerifyInterfaces (original, linked); + VerifyPseudoAttributes (original, linked); + VerifyGenericParameters (original, linked); + VerifyCustomAttributes (original, linked); + VerifySecurityAttributes (original, linked); + + VerifyFixedBufferFields (original, linked); + + foreach (var td in original.NestedTypes) { + VerifyTypeDefinition (td, linked?.NestedTypes.FirstOrDefault (l => td.FullName == l.FullName)); + linkedMembers.Remove (td.FullName); + } + + // Need to check properties before fields so that the KeptBackingFieldAttribute is handled correctly + foreach (var p in original.Properties) { + VerifyProperty (p, linked.Properties.FirstOrDefault (l => p.Name == l.Name), linked); + linkedMembers.Remove (p.FullName); + } + // Need to check events before fields so that the KeptBackingFieldAttribute is handled correctly + foreach (var e in original.Events) { + VerifyEvent (e, linked.Events.FirstOrDefault (l => e.Name == l.Name), linked); + linkedMembers.Remove (e.FullName); + } + + // Need to check delegate cache fields before the normal field check + VerifyDelegateBackingFields (original, linked); + + foreach (var f in original.Fields) { + if (verifiedGeneratedFields.Contains (f.FullName)) + continue; + VerifyField (f, linked.Fields.FirstOrDefault (l => f.Name == l.Name)); + linkedMembers.Remove (f.FullName); + } + + foreach (var m in original.Methods) { + if (verifiedEventMethods.Contains (m.FullName)) + continue; + var msign = m.GetSignature (); + VerifyMethod (m, linked.Methods.FirstOrDefault (l => msign == l.GetSignature ())); + linkedMembers.Remove (m.FullName); + } + } + + void VerifyBaseType (TypeDefinition src, TypeDefinition linked) + { + string expectedBaseName; + var expectedBaseGenericAttr = src.CustomAttributes.FirstOrDefault (w => w.AttributeType.Name == nameof (KeptBaseTypeAttribute) && w.ConstructorArguments.Count > 1); + if (expectedBaseGenericAttr != null) { + expectedBaseName = FormatBaseOrInterfaceAttributeValue (expectedBaseGenericAttr); + } else { + var defaultBaseType = src.IsEnum ? "System.Enum" : src.IsValueType ? "System.ValueType" : "System.Object"; + expectedBaseName = GetCustomAttributeCtorValues (src, nameof (KeptBaseTypeAttribute)).FirstOrDefault ()?.ToString () ?? defaultBaseType; + } + + if (expectedBaseName != linked.BaseType?.FullName) { + Assert.True (false, $"Incorrect base type on : {linked.Name}. Expected {expectedBaseName}, actual {linked.BaseType?.FullName}"); + } + } + + void VerifyInterfaces (TypeDefinition src, TypeDefinition linked) + { + var expectedInterfaces = new HashSet (src.CustomAttributes + .Where (w => w.AttributeType.Name == nameof (KeptInterfaceAttribute)) + .Select (FormatBaseOrInterfaceAttributeValue)); + if (expectedInterfaces.Count == 0) { + Assert.False (linked.HasInterfaces, $"Type `{src}' has unexpected interfaces"); + } else { + foreach (var iface in linked.Interfaces) { + if (!expectedInterfaces.Remove (iface.InterfaceType.FullName)) { + Assert.True (expectedInterfaces.Remove (iface.InterfaceType.Resolve ().FullName), $"Type `{src}' interface `{iface.InterfaceType.Resolve ().FullName}' should have been removed"); + } + } + + if (expectedInterfaces.Count != 0) + Assert.True (false, $"Expected interfaces were not found on {src}"); + } + } + + static string FormatBaseOrInterfaceAttributeValue (CustomAttribute attr) + { + if (attr.ConstructorArguments.Count == 1) + return attr.ConstructorArguments[0].Value.ToString ()!; + + StringBuilder builder = new StringBuilder (); + builder.Append (attr.ConstructorArguments[0].Value); + builder.Append ("<"); + bool separator = false; + foreach (var caa in (CustomAttributeArgument[]) attr.ConstructorArguments[1].Value) { + if (separator) + builder.Append (","); + else + separator = true; + + var arg = (CustomAttributeArgument) caa.Value; + builder.Append (arg.Value); + } + + builder.Append (">"); + return builder.ToString (); + } + + void VerifyField (FieldDefinition src, FieldDefinition? linked) + { + bool expectedKept = ShouldBeKept (src); + + if (!expectedKept) { + if (linked != null) + Assert.True (false, $"Field `{src}' should have been removed"); + + return; + } + + VerifyFieldKept (src, linked); + } + + void VerifyFieldKept (FieldDefinition src, FieldDefinition? linked) + { + if (linked == null) { + Assert.True (false, $"Field `{src}' should have been kept"); + return; + } + + if (!object.Equals (src.Constant, linked.Constant)) { + Assert.True (false, $"Field '{src}' value doesn's match. Expected {src.Constant}, actual {linked.Constant}"); + } + + VerifyPseudoAttributes (src, linked); + VerifyCustomAttributes (src, linked); + } + + void VerifyProperty (PropertyDefinition src, PropertyDefinition? linked, TypeDefinition linkedType) + { + VerifyMemberBackingField (src, linkedType); + + bool expectedKept = ShouldBeKept (src); + + if (!expectedKept) { + if (linked != null) + Assert.True (false, $"Property `{src}' should have been removed"); + + return; + } + + if (linked == null) { + Assert.True (false, $"Property `{src}' should have been kept"); + return; + } + + if (src.Constant != linked.Constant) { + Assert.True (false, $"Property '{src}' value doesn's match. Expected {src.Constant}, actual {linked.Constant}"); + } + + VerifyPseudoAttributes (src, linked); + VerifyCustomAttributes (src, linked); + } + + void VerifyEvent (EventDefinition src, EventDefinition? linked, TypeDefinition linkedType) + { + VerifyMemberBackingField (src, linkedType); + + bool expectedKept = ShouldBeKept (src); + + if (!expectedKept) { + if (linked != null) + Assert.True (false, $"Event `{src}' should have been removed"); + + return; + } + + if (linked == null) { + Assert.True (false, $"Event `{src}' should have been kept"); + return; + } + + if (src.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (KeptEventAddMethodAttribute))) { + VerifyMethodInternal (src.AddMethod, linked.AddMethod, true); + verifiedEventMethods.Add (src.AddMethod.FullName); + linkedMembers.Remove (src.AddMethod.FullName); + } + + if (src.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (KeptEventRemoveMethodAttribute))) { + VerifyMethodInternal (src.RemoveMethod, linked.RemoveMethod, true); + verifiedEventMethods.Add (src.RemoveMethod.FullName); + linkedMembers.Remove (src.RemoveMethod.FullName); + } + + VerifyPseudoAttributes (src, linked); + VerifyCustomAttributes (src, linked); + } + + void VerifyMethod (MethodDefinition src, MethodDefinition? linked) + { + bool expectedKept = ShouldMethodBeKept (src); + VerifyMethodInternal (src, linked, expectedKept); + } + + + void VerifyMethodInternal (MethodDefinition src, MethodDefinition? linked, bool expectedKept) + { + if (!expectedKept) { + if (linked != null) + Assert.True (false, $"Method `{src.FullName}' should have been removed"); + + return; + } + + VerifyMethodKept (src, linked); + } + + void VerifyMemberBackingField (IMemberDefinition src, TypeDefinition linkedType) + { + var keptBackingFieldAttribute = src.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (KeptBackingFieldAttribute)); + if (keptBackingFieldAttribute == null) + return; + + var backingFieldName = src.MetadataToken.TokenType == TokenType.Property + ? $"<{src.Name}>k__BackingField" : src.Name; + var srcField = src.DeclaringType.Fields.FirstOrDefault (f => f.Name == backingFieldName); + + if (srcField == null) { + // Can add more here if necessary + backingFieldName = backingFieldName.Replace ("System.Int32", "int"); + backingFieldName = backingFieldName.Replace ("System.String", "string"); + backingFieldName = backingFieldName.Replace ("System.Char", "char"); + + srcField = src.DeclaringType.Fields.FirstOrDefault (f => f.Name == backingFieldName); + } + + if (srcField == null) { + Assert.True (false, $"{src.MetadataToken.TokenType} `{src}', could not locate the expected backing field {backingFieldName}"); + return; + } + + VerifyFieldKept (srcField, linkedType?.Fields.FirstOrDefault (l => srcField.Name == l.Name)); + verifiedGeneratedFields.Add (srcField.FullName); + linkedMembers.Remove (srcField.FullName); + } + + protected virtual void VerifyMethodKept (MethodDefinition src, MethodDefinition? linked) + { + if (linked == null) { + Assert.True (false, $"Method `{src.FullName}' should have been kept"); + return; + } + + VerifyPseudoAttributes (src, linked); + VerifyGenericParameters (src, linked); + VerifyCustomAttributes (src, linked); + VerifyCustomAttributes (src.MethodReturnType, linked.MethodReturnType); + VerifyParameters (src, linked); + VerifySecurityAttributes (src, linked); + VerifyArrayInitializers (src, linked); + VerifyMethodBody (src, linked); + } + + protected virtual void VerifyMethodBody (MethodDefinition src, MethodDefinition linked) + { + if (!src.HasBody) + return; + + VerifyInstructions (src, linked); + VerifyLocals (src, linked); + } + + protected static void VerifyInstructions (MethodDefinition src, MethodDefinition linked) + { + VerifyBodyProperties ( + src, + linked, + nameof (ExpectedInstructionSequenceAttribute), + nameof (ExpectBodyModifiedAttribute), + "instructions", + m => FormatMethodBody (m.Body), + attr => GetStringArrayAttributeValue (attr)!.ToArray ()); + } + + public static string[] FormatMethodBody (MethodBody body) + { + List<(Instruction?, string)> result = new List<(Instruction?, string)> (body.Instructions.Count); + for (int index = 0; index < body.Instructions.Count; index++) { + var instruction = body.Instructions[index]; + result.Add ((instruction, FormatInstruction (instruction))); + } + + HashSet<(Instruction, Instruction)> existingTryBlocks = new HashSet<(Instruction, Instruction)> (); + foreach (var exHandler in body.ExceptionHandlers) { + if (existingTryBlocks.Add ((exHandler.TryStart, exHandler.TryEnd!))) { + InsertBeforeInstruction (exHandler.TryStart, ".try"); + if (exHandler.TryEnd != null) + InsertBeforeInstruction (exHandler.TryEnd, ".endtry"); + else + Append (".endtry"); + } + + if (exHandler.HandlerStart != null) + InsertBeforeInstruction (exHandler.HandlerStart, ".catch"); + + if (exHandler.HandlerEnd != null) + InsertBeforeInstruction (exHandler.HandlerEnd, ".endcatch"); + else + Append (".endcatch"); + + if (exHandler.FilterStart != null) + InsertBeforeInstruction (exHandler.FilterStart, ".filter"); + } + + return result.Select (i => i.Item2).ToArray (); + + void InsertBeforeInstruction (Instruction instruction, string text) => + result.Insert (result.FindIndex (i => i.Item1 == instruction), (null, text)); + + void Append (string text) => + result.Add ((null, text)); + } + + static string FormatInstruction (Instruction instr) + { + switch (instr.OpCode.FlowControl) { + case FlowControl.Branch: + case FlowControl.Cond_Branch: + if (instr.Operand is Instruction target) + return $"{instr.OpCode.ToString ()} il_{target.Offset.ToString ("x")}"; + + break; + } + + switch (instr.OpCode.Code) { + case Code.Ldc_I4: + if (instr.Operand is int ivalue) + return $"{instr.OpCode.ToString ()} 0x{ivalue.ToString ("x")}"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + case Code.Ldc_I4_S: + if (instr.Operand is sbyte bvalue) + return $"{instr.OpCode.ToString ()} 0x{bvalue.ToString ("x")}"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + case Code.Ldc_I8: + if (instr.Operand is long lvalue) + return $"{instr.OpCode.ToString ()} 0x{lvalue.ToString ("x")}"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + + case Code.Ldc_R4: + if (instr.Operand is float fvalue) + return $"{instr.OpCode.ToString ()} {fvalue.ToString ()}"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + + case Code.Ldc_R8: + if (instr.Operand is double dvalue) + return $"{instr.OpCode.ToString ()} {dvalue.ToString ()}"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + + case Code.Ldstr: + if (instr.Operand is string svalue) + return $"{instr.OpCode.ToString ()} '{svalue}'"; + + throw new NotImplementedException (instr.Operand.GetType ().ToString ()); + + default: { + string? operandString = null; + switch (instr.OpCode.OperandType) { + case OperandType.InlineField: + case OperandType.InlineMethod: + case OperandType.InlineType: + case OperandType.InlineTok: + operandString = instr.Operand switch { + FieldReference fieldRef => fieldRef.FullName, + MethodReference methodRef => methodRef.FullName, + TypeReference typeRef => typeRef.FullName, + _ => null + }; + break; + } + + if (operandString != null) + return $"{instr.OpCode.ToString ()} {operandString}"; + else + return instr.OpCode.ToString (); + } + } + } + static void VerifyLocals (MethodDefinition src, MethodDefinition linked) + { + VerifyBodyProperties ( + src, + linked, + nameof (ExpectedLocalsSequenceAttribute), + nameof (ExpectLocalsModifiedAttribute), + "locals", + m => m.Body.Variables.Select (v => v.VariableType.ToString ()).ToArray (), + attr => GetStringOrTypeArrayAttributeValue (attr).ToArray ()); + } + + public static void VerifyBodyProperties (MethodDefinition src, MethodDefinition linked, string sequenceAttributeName, string expectModifiedAttributeName, + string propertyDescription, + Func valueCollector, + Func getExpectFromSequenceAttribute) + { + var expectedSequenceAttribute = src.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == sequenceAttributeName); + var linkedValues = valueCollector (linked); + var srcValues = valueCollector (src); + + if (src.CustomAttributes.Any (attr => attr.AttributeType.Name == expectModifiedAttributeName)) { + linkedValues.Should ().BeEquivalentTo (srcValues, $"Expected method `{src} to have {propertyDescription} modified, however, the {propertyDescription} were the same as the original\n{FormattingUtils.FormatSequenceCompareFailureMessage (linkedValues, srcValues)}"); + } else if (expectedSequenceAttribute != null) { + var expected = getExpectFromSequenceAttribute (expectedSequenceAttribute).ToArray (); + linkedValues.Should ().BeEquivalentTo (expected, $"Expected method `{src} to have it's {propertyDescription} modified, however, the sequence of {propertyDescription} does not match the expected value\n{FormattingUtils.FormatSequenceCompareFailureMessage2 (linkedValues, expected, srcValues)}"); + } else { + linkedValues.Should ().BeEquivalentTo (srcValues, $"Expected method `{src} to have it's {propertyDescription} unchanged, however, the {propertyDescription} differ from the original\n{FormattingUtils.FormatSequenceCompareFailureMessage (linkedValues, srcValues)}"); + } + } + + void VerifyReferences (AssemblyDefinition original, AssemblyDefinition linked) + { + var expected = original.MainModule.AllDefinedTypes () + .SelectMany (t => GetCustomAttributeCtorValues (t, nameof (KeptReferenceAttribute))) + .Select (ReduceAssemblyFileNameOrNameToNameOnly) + .ToArray (); + + /* + - The test case will always need to have at least 1 reference. + - Forcing all tests to define their expected references seems tedious + + Given the above, let's assume that when no [KeptReference] attributes are present, + the test case does not want to make any assertions regarding references. + + Once 1 kept reference attribute is used, the test will need to define all of of it's expected references + */ + if (expected.Length == 0) + return; + + var actual = linked.MainModule.AssemblyReferences + .Select (name => name.Name) + .ToArray (); + + actual.Should ().BeEquivalentTo (expected); + } + + string? ReduceAssemblyFileNameOrNameToNameOnly (string? fileNameOrAssemblyName) + { + if (fileNameOrAssemblyName == null) + return null; + + if (fileNameOrAssemblyName.EndsWith (".dll") || fileNameOrAssemblyName.EndsWith (".exe") || fileNameOrAssemblyName.EndsWith (".winmd")) + return System.IO.Path.GetFileNameWithoutExtension (fileNameOrAssemblyName); + + // It must already be just the assembly name + return fileNameOrAssemblyName; + } + + void VerifyResources (AssemblyDefinition original, AssemblyDefinition linked) + { + var expectedResourceNames = original.MainModule.AllDefinedTypes () + .SelectMany (t => GetCustomAttributeCtorValues (t, nameof (KeptResourceAttribute))) + .ToList (); + + foreach (var resource in linked.MainModule.Resources) { + if (!expectedResourceNames.Remove (resource.Name)) + Assert.True (false, $"Resource '{resource.Name}' should be removed."); + + EmbeddedResource embeddedResource = (EmbeddedResource) resource; + + var expectedResource = (EmbeddedResource) original.MainModule.Resources.First (r => r.Name == resource.Name); + + embeddedResource.GetResourceData ().Should ().BeEquivalentTo (expectedResource.GetResourceData (), $"Resource '{resource.Name}' data doesn't match."); + } + + if (expectedResourceNames.Count > 0) { + Assert.True (false, $"Resource '{expectedResourceNames.First ()}' should be kept."); + } + } + + void VerifyExportedTypes (AssemblyDefinition original, AssemblyDefinition linked) + { + var expectedTypes = original.MainModule.AllDefinedTypes () + .SelectMany (t => GetCustomAttributeCtorValues (t, nameof (KeptExportedTypeAttribute)).Select (l => l?.FullName ?? "")).ToArray (); + + linked.MainModule.ExportedTypes.Select (l => l.FullName).Should ().BeEquivalentTo (expectedTypes); + } + + protected virtual void VerifyPseudoAttributes (MethodDefinition src, MethodDefinition linked) + { + var expected = (MethodAttributes) GetExpectedPseudoAttributeValue (src, (uint) src.Attributes); + linked.Attributes.Should ().Be (expected, $"Method `{src}' pseudo attributes did not match expected"); + } + + protected virtual void VerifyPseudoAttributes (TypeDefinition src, TypeDefinition linked) + { + var expected = (TypeAttributes) GetExpectedPseudoAttributeValue (src, (uint) src.Attributes); + linked.Attributes.Should ().Be (expected, $"Type `{src}' pseudo attributes did not match expected"); + } + + protected virtual void VerifyPseudoAttributes (FieldDefinition src, FieldDefinition linked) + { + var expected = (FieldAttributes) GetExpectedPseudoAttributeValue (src, (uint) src.Attributes); + linked.Attributes.Should ().Be (expected, $"Field `{src}' pseudo attributes did not match expected"); + } + + protected virtual void VerifyPseudoAttributes (PropertyDefinition src, PropertyDefinition linked) + { + var expected = (PropertyAttributes) GetExpectedPseudoAttributeValue (src, (uint) src.Attributes); + linked.Attributes.Should ().Be (expected, $"Property `{src}' pseudo attributes did not match expected"); + } + + protected virtual void VerifyPseudoAttributes (EventDefinition src, EventDefinition linked) + { + var expected = (EventAttributes) GetExpectedPseudoAttributeValue (src, (uint) src.Attributes); + linked.Attributes.Should ().Be (expected, $"Event `{src}' pseudo attributes did not match expected"); + } + + protected virtual void VerifyCustomAttributes (ICustomAttributeProvider src, ICustomAttributeProvider linked) + { + var expectedAttrs = GetExpectedAttributes (src).ToList (); + var linkedAttrs = FilterLinkedAttributes (linked).ToList (); + + linkedAttrs.Should ().BeEquivalentTo (expectedAttrs, $"Custom attributes on `{src}' are not matching"); + } + + protected virtual void VerifySecurityAttributes (ICustomAttributeProvider src, ISecurityDeclarationProvider linked) + { + var expectedAttrs = GetCustomAttributeCtorValues (src, nameof (KeptSecurityAttribute)) + .Select (attr => attr?.ToString () ?? "") + .ToList (); + + var linkedAttrs = FilterLinkedSecurityAttributes (linked).ToList (); + + linkedAttrs.Should ().BeEquivalentTo (expectedAttrs, $"Security attributes on `{src}' are not matching"); + } + + protected virtual void VerifyArrayInitializers (MethodDefinition src, MethodDefinition linked) + { + var expectedIndicies = GetCustomAttributeCtorValues (src, nameof (KeptInitializerData)) + .Cast () + .ToArray (); + + var expectKeptAll = src.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (KeptInitializerData) && !attr.HasConstructorArguments); + + if (expectedIndicies.Length == 0 && !expectKeptAll) + return; + + if (!src.HasBody) + Assert.True (false, $"`{nameof (KeptInitializerData)}` cannot be used on methods that don't have bodies"); + + var srcImplementationDetails = src.Module.Types.FirstOrDefault (t => string.IsNullOrEmpty (t.Namespace) && t.Name.StartsWith ("")); + + if (srcImplementationDetails == null) { + Assert.True (false, "Could not locate in the original assembly. Does your test use initializers?"); + return; + } + + var linkedImplementationDetails = linked.Module.Types.FirstOrDefault (t => string.IsNullOrEmpty (t.Namespace) && t.Name.StartsWith ("")); + + if (linkedImplementationDetails == null) { + Assert.True (false, "Could not locate in the linked assembly"); + return; + } + + var possibleInitializerFields = src.Body.Instructions + .Where (ins => IsLdtokenOnPrivateImplementationDetails (srcImplementationDetails, ins)) + .Select (ins => ((FieldReference) ins.Operand).Resolve ()) + .ToArray (); + + if (possibleInitializerFields.Length == 0) + Assert.True (false, $"`{src}` does not make use of any initializers"); + + if (expectKeptAll) { + foreach (var srcField in possibleInitializerFields) { + var linkedField = linkedImplementationDetails.Fields.FirstOrDefault (f => f.InitialValue.SequenceEqual (srcField.InitialValue)); + VerifyInitializerField (srcField, linkedField); + } + } else { + foreach (var index in expectedIndicies) { + if (index < 0 || index > possibleInitializerFields.Length) + Assert.True (false, $"Invalid expected index `{index}` in {src}. Value must be between 0 and {expectedIndicies.Length}"); + + var srcField = possibleInitializerFields[index]; + var linkedField = linkedImplementationDetails.Fields.FirstOrDefault (f => f.InitialValue.SequenceEqual (srcField.InitialValue)); + + VerifyInitializerField (srcField, linkedField); + } + } + } + + void VerifyInitializerField (FieldDefinition src, FieldDefinition? linked) + { + VerifyFieldKept (src, linked); + verifiedGeneratedFields.Add (linked!.FullName); + linkedMembers.Remove (linked.FullName); + VerifyTypeDefinitionKept (src.FieldType.Resolve (), linked.FieldType.Resolve ()); + linkedMembers.Remove (linked.FieldType.FullName); + linkedMembers.Remove (linked.DeclaringType.FullName); + verifiedGeneratedTypes.Add (linked.DeclaringType.FullName); + } + + static bool IsLdtokenOnPrivateImplementationDetails (TypeDefinition privateImplementationDetails, Instruction instruction) + { + if (instruction.OpCode.Code == Code.Ldtoken && instruction.Operand is FieldReference field) { + return field.DeclaringType.Resolve () == privateImplementationDetails; + } + + return false; + } + + protected static IEnumerable GetExpectedAttributes (ICustomAttributeProvider original) + { + foreach (var expectedAttrs in GetCustomAttributeCtorValues (original, nameof (KeptAttributeAttribute))) + yield return expectedAttrs?.ToString (); + + // The name of the generated fixed buffer type is a little tricky. + // Some versions of csc name it `e__FixedBuffer0` + // while mcs and other versions of csc name it `__FixedBuffer0` + if (original is TypeDefinition srcDefinition && srcDefinition.Name.Contains ("__FixedBuffer")) { + var name = srcDefinition.Name.Substring (1, srcDefinition.Name.IndexOf ('>') - 1); + var fixedField = srcDefinition.DeclaringType.Fields.FirstOrDefault (f => f.Name == name); + if (fixedField == null) + Assert.True (false, $"Could not locate original fixed field for {srcDefinition}"); + + foreach (var additionalExpectedAttributesFromFixedField in GetCustomAttributeCtorValues (fixedField!, nameof (KeptAttributeOnFixedBufferTypeAttribute))) + yield return additionalExpectedAttributesFromFixedField?.ToString (); + + } + } + + /// + /// Filters out some attributes that should not be taken into consideration when checking the linked result against the expected result + /// + /// + /// + protected virtual IEnumerable FilterLinkedAttributes (ICustomAttributeProvider linked) + { + foreach (var attr in linked.CustomAttributes) { + switch (attr.AttributeType.FullName) { + case "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute": + case "System.Runtime.CompilerServices.CompilerGeneratedAttribute": + continue; + + // When mcs is used to compile the test cases, backing fields end up with this attribute on them + case "System.Diagnostics.DebuggerBrowsableAttribute": + continue; + + // When compiling with roslyn, assemblies get the DebuggableAttribute by default. + case "System.Diagnostics.DebuggableAttribute": + continue; + + case "System.Runtime.CompilerServices.CompilationRelaxationsAttribute": + if (linked is AssemblyDefinition) + continue; + break; + } + + yield return attr.AttributeType.FullName; + } + } + + protected virtual IEnumerable FilterLinkedSecurityAttributes (ISecurityDeclarationProvider linked) + { + return linked.SecurityDeclarations + .SelectMany (d => d.SecurityAttributes) + .Select (attr => attr.AttributeType.ToString ()); + } + + void VerifyFixedBufferFields (TypeDefinition src, TypeDefinition linked) + { + var fields = src.Fields.Where (f => f.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (KeptFixedBufferAttribute))); + + foreach (var field in fields) { + // The name of the generated fixed buffer type is a little tricky. + // Some versions of csc name it `e__FixedBuffer0` + // while mcs and other versions of csc name it `__FixedBuffer0` + var originalCompilerGeneratedBufferType = src.NestedTypes.FirstOrDefault (t => t.FullName.Contains ($"<{field.Name}>") && t.FullName.Contains ("__FixedBuffer")); + if (originalCompilerGeneratedBufferType == null) { + Assert.True (false, $"Could not locate original compiler generated fixed buffer type for field {field}"); + return; + } + + var linkedCompilerGeneratedBufferType = linked.NestedTypes.FirstOrDefault (t => t.Name == originalCompilerGeneratedBufferType.Name); + if (linkedCompilerGeneratedBufferType == null) { + Assert.True (false, $"Missing expected type {originalCompilerGeneratedBufferType}"); + return; + } + + // Have to verify the field before the type + var originalElementField = originalCompilerGeneratedBufferType.Fields.FirstOrDefault (); + if (originalElementField == null) { + Assert.True (false, $"Could not locate original compiler generated FixedElementField on {originalCompilerGeneratedBufferType}"); + return; + } + + var linkedField = linkedCompilerGeneratedBufferType?.Fields.FirstOrDefault (); + VerifyFieldKept (originalElementField, linkedField); + verifiedGeneratedFields.Add (originalElementField.FullName); + linkedMembers.Remove (linkedField!.FullName); + + VerifyTypeDefinitionKept (originalCompilerGeneratedBufferType, linkedCompilerGeneratedBufferType); + verifiedGeneratedTypes.Add (originalCompilerGeneratedBufferType.FullName); + } + } + + void VerifyDelegateBackingFields (TypeDefinition src, TypeDefinition linked) + { + var expectedFieldNames = GetCustomAttributeCtorValues (src, nameof (KeptDelegateCacheFieldAttribute)) + .Select (unique => $"<>f__mg$cache{unique}") + .ToList (); + + if (expectedFieldNames.Count == 0) + return; + + foreach (var srcField in src.Fields) { + if (!expectedFieldNames.Contains (srcField.Name)) + continue; + + var linkedField = linked?.Fields.FirstOrDefault (l => l.Name == srcField.Name); + VerifyFieldKept (srcField, linkedField); + verifiedGeneratedFields.Add (srcField.FullName); + linkedMembers.Remove (srcField.FullName); + } + } + + void VerifyGenericParameters (IGenericParameterProvider src, IGenericParameterProvider linked) + { + Assert.Equal (src.HasGenericParameters, linked.HasGenericParameters); + if (src.HasGenericParameters) { + for (int i = 0; i < src.GenericParameters.Count; ++i) { + // TODO: Verify constraints + var srcp = src.GenericParameters[i]; + var lnkp = linked.GenericParameters[i]; + VerifyCustomAttributes (srcp, lnkp); + + if (checkNames) { + if (srcp.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (RemovedNameValueAttribute))) { + string name = (src.GenericParameterType == GenericParameterType.Method ? "!!" : "!") + srcp.Position; + lnkp.Name.Should ().Be (name, "Expected empty generic parameter name"); + } else { + lnkp.Name.Should ().Be (srcp.Name, "Mismatch in generic parameter name"); + } + } + } + } + } + + void VerifyParameters (IMethodSignature src, IMethodSignature linked) + { + Assert.Equal (src.HasParameters, linked.HasParameters); + if (src.HasParameters) { + for (int i = 0; i < src.Parameters.Count; ++i) { + var srcp = src.Parameters[i]; + var lnkp = linked.Parameters[i]; + + VerifyCustomAttributes (srcp, lnkp); + + if (checkNames) { + if (srcp.CustomAttributes.Any (attr => attr.AttributeType.Name == nameof (RemovedNameValueAttribute))) + lnkp.Name.Should ().BeEmpty ("Expected empty parameter name"); + else + lnkp.Name.Should ().Be (srcp.Name, "Mismatch in parameter name"); + } + } + } + } + + protected virtual bool ShouldMethodBeKept (MethodDefinition method) + { + var srcSignature = method.GetSignature (); + return ShouldBeKept (method, srcSignature) || method.DeclaringType.Module.EntryPoint == method; + } + + protected virtual bool ShouldBeKept (T member, string? signature = null) where T : MemberReference, ICustomAttributeProvider + { + if (member.HasAttribute (nameof (KeptAttribute))) + return true; + + ICustomAttributeProvider cap = (ICustomAttributeProvider) member.DeclaringType; + if (cap == null) + return false; + + return GetCustomAttributeCtorValues (cap, nameof (KeptMemberAttribute)).Any (a => a == (signature ?? member.Name)); + } + + protected static uint GetExpectedPseudoAttributeValue (ICustomAttributeProvider provider, uint sourceValue) + { + var removals = provider.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (RemovedPseudoAttributeAttribute)).ToArray (); + var adds = provider.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (AddedPseudoAttributeAttribute)).ToArray (); + + return removals.Aggregate (sourceValue, (accum, item) => accum & ~(uint) item.ConstructorArguments[0].Value) | + adds.Aggregate ((uint) 0, (acum, item) => acum | (uint) item.ConstructorArguments[0].Value); + } + + protected static IEnumerable GetCustomAttributeCtorValues (ICustomAttributeProvider provider, string attributeName) where T : class + { + return provider.CustomAttributes. + Where (w => w.AttributeType.Name == attributeName && w.Constructor.Parameters.Count == 1). + Select (l => l.ConstructorArguments[0].Value as T); + } + + protected static IEnumerable GetStringOrTypeArrayAttributeValue (CustomAttribute attribute) + { + foreach (var arg in (CustomAttributeArgument[]) attribute.ConstructorArguments[0].Value) { + if (arg.Value is TypeReference tRef) + yield return tRef.ToString (); + else + yield return (string) arg.Value; + } + } + + protected static IEnumerable? GetStringArrayAttributeValue (CustomAttribute attribute) + { + return ((CustomAttributeArgument[]) attribute.ConstructorArguments[0].Value)?.Select (arg => arg.Value.ToString ()!); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/BaseMetadataProvider.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/BaseMetadataProvider.cs new file mode 100644 index 0000000000000..b136da80846b4 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/BaseMetadataProvider.cs @@ -0,0 +1,96 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using Mono.Cecil; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public abstract class BaseMetadataProvider + { + protected readonly TestCase _testCase; + protected readonly TypeDefinition _testCaseTypeDefinition; + + protected BaseMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition) + { + _testCase = testCase; + // The test case types are never nested so we don't need to worry about that + _testCaseTypeDefinition = fullTestCaseAssemblyDefinition.MainModule.GetType (_testCase.ReconstructedFullTypeName); + + if (_testCaseTypeDefinition == null) + throw new InvalidOperationException ($"Could not find the type definition for {_testCase.Name} in {_testCase.SourceFile}"); + } + + protected T? GetOptionAttributeValue (string attributeName, T? defaultValue) + { + var attribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == attributeName); + if (attribute != null) + return (T?) attribute.ConstructorArguments.First ().Value; + + return defaultValue; + } + + protected NPath MakeSourceTreeFilePathAbsolute (string value) + { + return _testCase.SourceFile.Parent.Combine (value); + } + + protected SourceAndDestinationPair GetSourceAndRelativeDestinationValue (CustomAttribute attribute) + { + var fullSource = SourceFileForAttributeArgumentValue (attribute.ConstructorArguments.First ().Value); + var destinationFileName = (string) attribute.ConstructorArguments[1].Value; + return new SourceAndDestinationPair { + Source = fullSource, + DestinationFileName = string.IsNullOrEmpty (destinationFileName) ? fullSource.FileName : destinationFileName + }; + } + + + protected virtual NPath SourceFileForAttributeArgumentValue (object value) + { + if (value is TypeReference valueAsTypeRef) { + // Use the parent type for locating the source file + var parentType = ParentMostType (valueAsTypeRef); + var pathRelativeToAssembly = $"{parentType.FullName.Substring (parentType.Module.Name.Length - 3).Replace ('.', '/')}.cs".ToNPath (); + var pathElements = pathRelativeToAssembly.Elements.ToArray (); + var topMostDirectoryName = pathElements[0]; + var topMostDirectory = _testCase.SourceFile.RecursiveParents.Reverse ().FirstOrDefault (d => !d.IsRoot && d.FileName == topMostDirectoryName); + + if (topMostDirectory == null) { + // Before giving up, try and detect the naming scheme for tests that use a dot in the top level directory name. + // Ex: + // Attributes.Debugger + // + 1 because the file name is one of the elements + if (pathElements.Length >= 3) { + topMostDirectoryName = $"{pathElements[0]}.{pathElements[1]}"; + topMostDirectory = _testCase.SourceFile.RecursiveParents.Reverse ().FirstOrDefault (d => !d.IsRoot && d.FileName == topMostDirectoryName); + pathRelativeToAssembly = topMostDirectoryName.ToNPath ().Combine (pathElements.Skip (2).Aggregate (new NPath (string.Empty), (path, s) => path.Combine (s))); + } + + if (topMostDirectory == null) + throw new ArgumentException ($"Unable to locate the source file for type {valueAsTypeRef}. Could not locate directory {topMostDirectoryName}. Ensure the type name matches the file name. And the namespace match the directory structure on disk"); + } + + var fullPath = topMostDirectory.Parent.Combine (pathRelativeToAssembly); + + if (!fullPath.Exists ()) + throw new ArgumentException ($"Unable to locate the source file for type {valueAsTypeRef}. Expected {fullPath}. Ensure the type name matches the file name. And the namespace match the directory structure on disk"); + + return fullPath; + } + + return MakeSourceTreeFilePathAbsolute (value.ToString ()!); + } + + static TypeReference ParentMostType (TypeReference type) + { + if (!type.IsNested) + return type; + + return ParentMostType (type.DeclaringType); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/CompilerOptions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/CompilerOptions.cs new file mode 100644 index 0000000000000..852576c73dfa0 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/CompilerOptions.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Linker.Tests.Extensions; + +#nullable disable + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class CompilerOptions + { + public NPath OutputPath; + public NPath[] SourceFiles; + public string[] Defines; + public NPath[] References; + public NPath[] Resources; + public string[] AdditionalArguments; + public string CompilerToUse; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ExpectationsProvider.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ExpectationsProvider.cs new file mode 100644 index 0000000000000..7ca189d9befbd --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ExpectationsProvider.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Cecil; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public static class ExpectationsProvider + { + + public static bool IsAssemblyAssertion (CustomAttribute attr) + { + return attr.AttributeType.Name == nameof (KeptAssemblyAttribute) || + attr.AttributeType.Name == nameof (RemovedAssemblyAttribute) || + attr.AttributeType.Name == nameof (SetupLinkerActionAttribute) || + attr.AttributeType.Name == nameof (SetupLinkerTrimModeAttribute); + } + + public static bool IsSymbolAssertion (CustomAttribute attr) + { + return attr.AttributeType.Name == nameof (KeptSymbolsAttribute) || attr.AttributeType.Name == nameof (RemovedSymbolsAttribute); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/FormattingUtils.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/FormattingUtils.cs new file mode 100644 index 0000000000000..108e065098add --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/FormattingUtils.cs @@ -0,0 +1,64 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public static class FormattingUtils + { + public static string FormatSequenceCompareFailureMessage (IEnumerable actual, IEnumerable expected) + { + var builder = new StringBuilder (); + builder.AppendLine ("---------------"); + builder.AppendLine ($"Expected/Original (Total : {expected.Count ()})"); + builder.AppendLine ("---------------"); + // Format in a quoted array form for easier copying into a expected sequence attribute + builder.AppendLine (expected.Select (c => $"\"{c}\",").AggregateWithNewLine ()); + builder.AppendLine ("---------------"); + builder.AppendLine ($"Actual/Linked (Total : {actual.Count ()})"); + builder.AppendLine ("---------------"); + // Format in a quoted array form for easier copying into a expected sequence attribute + builder.AppendLine (actual.Select (c => $"\"{c}\",").AggregateWithNewLine ()); + builder.AppendLine ("---------------"); + return builder.ToString (); + } + + public static string FormatSequenceCompareFailureMessage2 (IEnumerable actual, IEnumerable expected, IEnumerable original) + { + var builder = new StringBuilder (); + builder.AppendLine ("---------------"); + builder.AppendLine ($"Expected (Total : {expected.Count ()})"); + builder.AppendLine ("---------------"); + // Format in a quoted array form for easier copying into a expected sequence attribute + builder.AppendLine (expected.Select (c => $"\"{c}\",").AggregateWithNewLine ()); + builder.AppendLine ("---------------"); + builder.AppendLine ($"Actual/Linked (Total : {actual.Count ()})"); + builder.AppendLine ("---------------"); + // Format in a quoted array form for easier copying into a expected sequence attribute + builder.AppendLine (actual.Select (c => $"\"{c}\",").AggregateWithNewLine ()); + builder.AppendLine ("---------------"); + builder.AppendLine ($"Original (Total : {original.Count ()})"); + builder.AppendLine ("---------------"); + // Format in a quoted array form for easier copying into a expected sequence attribute + builder.AppendLine (original.Select (c => $"\"{c}\",").AggregateWithNewLine ()); + builder.AppendLine ("---------------"); + return builder.ToString (); + } + + private static string AggregateWithNewLine (this IEnumerable elements) + { + return elements.AggregateWith (System.Environment.NewLine); + } + + private static string AggregateWith (this IEnumerable elements, string separator) + { + if (elements.Any ()) + return elements.Aggregate ((buff, s) => buff + separator + s); + + return string.Empty; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs new file mode 100644 index 0000000000000..a0eff369ee98a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerDriver.cs @@ -0,0 +1,137 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using ILCompiler; +using ILLink.Shared.TrimAnalysis; +using Internal.IL; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ILCompilerDriver + { + private const string DefaultSystemModule = "System.Private.CoreLib"; + + public void Trim (ILCompilerOptions options, ILogWriter logWriter) + { + ComputeDefaultOptions (out var targetOS, out var targetArchitecture); + var targetDetails = new TargetDetails (targetArchitecture, targetOS, TargetAbi.NativeAot); + CompilerTypeSystemContext typeSystemContext = + new CompilerTypeSystemContext (targetDetails, SharedGenericsMode.CanonicalReferenceTypes, DelegateFeature.All); + + typeSystemContext.InputFilePaths = options.InputFilePaths; + typeSystemContext.ReferenceFilePaths = options.ReferenceFilePaths; + typeSystemContext.SetSystemModule (typeSystemContext.GetModuleForSimpleName (DefaultSystemModule)); + + List inputModules = new List (); + foreach (var inputFile in typeSystemContext.InputFilePaths) { + EcmaModule module = typeSystemContext.GetModuleFromPath (inputFile.Value); + inputModules.Add (module); + } + + CompilationModuleGroup compilationGroup = new MultiFileSharedCompilationModuleGroup (typeSystemContext, inputModules); + + List compilationRoots = new List (); + EcmaModule? entrypointModule = null; + foreach (var inputFile in typeSystemContext.InputFilePaths) { + EcmaModule module = typeSystemContext.GetModuleFromPath (inputFile.Value); + + if (module.PEReader.PEHeaders.IsExe) { + if (entrypointModule != null) + throw new Exception ("Multiple EXE modules"); + entrypointModule = module; + } + + compilationRoots.Add (new ExportedMethodsRootProvider (module)); + } + + compilationRoots.Add (new MainMethodRootProvider (entrypointModule, CreateInitializerList (typeSystemContext, options))); + + ILProvider ilProvider = new NativeAotILProvider (); + + ilProvider = new FeatureSwitchManager (ilProvider, options.FeatureSwitches); + + Logger logger = new Logger (logWriter, isVerbose: true); + + UsageBasedMetadataManager metadataManager = new UsageBasedMetadataManager ( + compilationGroup, + typeSystemContext, + new NoMetadataBlockingPolicy (), + new ManifestResourceBlockingPolicy (options.FeatureSwitches), + logFile: null, + new NoStackTraceEmissionPolicy (), + new NoDynamicInvokeThunkGenerationPolicy (), + new FlowAnnotations (logger, ilProvider), + UsageBasedMetadataGenerationOptions.ReflectionILScanning, + logger, + Array.Empty> (), + Array.Empty (), + options.TrimAssemblies.ToArray ()); + + CompilationBuilder builder = new RyuJitCompilationBuilder (typeSystemContext, compilationGroup) + .UseILProvider (ilProvider) + .UseCompilationUnitPrefix(""); + + IILScanner scanner = builder.GetILScannerBuilder () + .UseCompilationRoots (compilationRoots) + .UseMetadataManager (metadataManager) + .UseParallelism (System.Diagnostics.Debugger.IsAttached ? 1 : -1) + .ToILScanner (); + + ILScanResults results = scanner.Scan (); + } + + public static void ComputeDefaultOptions (out TargetOS os, out TargetArchitecture arch) + { + if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) + os = TargetOS.Windows; + else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) + os = TargetOS.Linux; + else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) + os = TargetOS.OSX; + else if (RuntimeInformation.IsOSPlatform (OSPlatform.FreeBSD)) + os = TargetOS.FreeBSD; + else + throw new NotImplementedException (); + + switch (RuntimeInformation.ProcessArchitecture) { + case Architecture.X86: + arch = TargetArchitecture.X86; + break; + case Architecture.X64: + arch = TargetArchitecture.X64; + break; + case Architecture.Arm: + arch = TargetArchitecture.ARM; + break; + case Architecture.Arm64: + arch = TargetArchitecture.ARM64; + break; + default: + throw new NotImplementedException (); + } + } + + private IReadOnlyCollection CreateInitializerList (CompilerTypeSystemContext context, ILCompilerOptions options) + { + List assembliesWithInitalizers = new List (); + + // Build a list of assemblies that have an initializer that needs to run before + // any user code runs. + foreach (string initAssemblyName in options.InitAssemblies) { + ModuleDesc assembly = context.ResolveAssembly (new AssemblyName (initAssemblyName), throwIfNotFound: true); + assembliesWithInitalizers.Add (assembly); + } + + var libraryInitializers = new LibraryInitializers (context, assembliesWithInitalizers); + + List initializerList = new List (libraryInitializers.LibraryInitializerMethods); + return initializerList; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptions.cs new file mode 100644 index 0000000000000..7bba7ae4de334 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptions.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ILCompilerOptions + { + public Dictionary InputFilePaths = new Dictionary (); + public Dictionary ReferenceFilePaths = new Dictionary (); + public List InitAssemblies = new List (); + public List TrimAssemblies = new List (); + public Dictionary FeatureSwitches = new Dictionary (); + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptionsBuilder.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptionsBuilder.cs new file mode 100644 index 0000000000000..98f0ee4351ef1 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerOptionsBuilder.cs @@ -0,0 +1,253 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using Mono.Linker.Tests.Extensions; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ILCompilerOptionsBuilder + { + //public TrimmerOptions Options { get; } = new(); + private readonly TestCaseMetadataProvider _metadataProvider; + + public readonly ILCompilerOptions Options; + + public ILCompilerOptionsBuilder (TestCaseMetadataProvider metadataProvider) + { + Options = new ILCompilerOptions (); + _metadataProvider = metadataProvider; + + string runtimeBinDir = (string) AppContext.GetData ("Mono.Linker.Tests.RuntimeBinDirectory")!; + AppendExpandedPaths (Options.ReferenceFilePaths, Path.Combine (runtimeBinDir, "aotsdk", "*.dll")); + + string runtimePackDir = (string) AppContext.GetData ("Mono.Linker.Tests.MicrosoftNetCoreAppRuntimePackDirectory")!; + if (!Directory.Exists (runtimePackDir) && runtimePackDir.Contains ("Debug")) { + // Frequently we'll have a Debug runtime and Release libraries, which actually produces a Release runtime pack + // but from within VS we're see Debug everything. So if the runtime pack directory doesn't exist + // try the Release path (simple string replace) + string candidate = runtimePackDir.Replace ("Debug", "Release"); + if (Directory.Exists (candidate)) + runtimePackDir = candidate; + } + AppendExpandedPaths (Options.ReferenceFilePaths, Path.Combine (runtimePackDir, "*.dll")); + + Options.InitAssemblies.Add ("System.Private.CoreLib"); + Options.InitAssemblies.Add ("System.Private.StackTraceMetadata"); + Options.InitAssemblies.Add ("System.Private.TypeLoader"); + Options.InitAssemblies.Add ("System.Private.Reflection.Execution"); + + Options.FeatureSwitches.Add ("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", false); + Options.FeatureSwitches.Add ("System.Resources.ResourceManager.AllowCustomResourceTypes", false); + Options.FeatureSwitches.Add ("System.Linq.Expressions.CanCompileToIL", false); + Options.FeatureSwitches.Add ("System.Linq.Expressions.CanEmitObjectArrayDelegate", false); + Options.FeatureSwitches.Add ("System.Linq.Expressions.CanCreateArbitraryDelegates", false); + } + + public virtual void AddSearchDirectory (NPath directory) + { + } + + public virtual void AddReference (NPath path) + { + AppendExpandedPaths (Options.ReferenceFilePaths, path.ToString ()); + } + + public virtual void AddOutputDirectory (NPath directory) + { + } + + public virtual void AddLinkXmlFile (string file) + { + } + + public virtual void AddResponseFile (NPath path) + { + } + + public virtual void AddTrimMode (string value) + { + } + + public virtual void AddDefaultAction (string value) + { + } + + public virtual void AddLinkAssembly (string fileName) + { + Options.TrimAssemblies.Add (fileName); + } + + public virtual void LinkFromAssembly (string fileName) + { + AppendExpandedPaths (Options.InputFilePaths, fileName); + } + + public virtual void LinkFromPublicAndFamily (string fileName) + { + } + + public virtual void IgnoreDescriptors (bool value) + { + } + + public virtual void IgnoreSubstitutions (bool value) + { + } + + public virtual void IgnoreLinkAttributes (bool value) + { + } + + public virtual void AddIl8n (string value) + { + } + + public virtual void AddKeepTypeForwarderOnlyAssemblies (string value) + { + } + + public virtual void AddLinkSymbols (string value) + { + } + + public virtual void AddKeepDebugMembers (string value) + { + } + + public virtual void AddAssemblyAction (string action, string assembly) + { + } + + public virtual void AddSkipUnresolved (bool skipUnresolved) + { + } + + public virtual void AddStripDescriptors (bool stripDescriptors) + { + } + + public virtual void AddStripSubstitutions (bool stripSubstitutions) + { + } + + public virtual void AddStripLinkAttributes (bool stripLinkAttributes) + { + } + + public virtual void AddSubstitutions (string file) + { + } + + public virtual void AddLinkAttributes (string file) + { + } + + public virtual void AddAdditionalArgument (string flag, string[] values) + { + if (flag == "--feature") { + Options.FeatureSwitches.Add (values[0], bool.Parse (values[1])); + } + } + + public virtual void ProcessTestInputAssembly (NPath inputAssemblyPath) + { + if (_metadataProvider.LinkPublicAndFamily ()) + LinkFromPublicAndFamily (inputAssemblyPath.ToString ()); + else + LinkFromAssembly (inputAssemblyPath.ToString ()); + } + + public virtual void ProcessOptions (TestCaseLinkerOptions options) + { + if (options.TrimMode != null) + AddTrimMode (options.TrimMode); + + if (options.DefaultAssembliesAction != null) + AddDefaultAction (options.DefaultAssembliesAction); + + if (options.AssembliesAction != null) { + foreach (var (action, assembly) in options.AssembliesAction) + AddAssemblyAction (action, assembly); + } + + // Honoring descriptors causes a ton of stuff to be preserved. That's good for normal use cases, but for + // our test cases that pollutes the results + IgnoreDescriptors (options.IgnoreDescriptors); + + IgnoreSubstitutions (options.IgnoreSubstitutions); + + IgnoreLinkAttributes (options.IgnoreLinkAttributes); + +#if !NETCOREAPP + if (!string.IsNullOrEmpty (options.Il8n)) + AddIl8n (options.Il8n); +#endif + + if (!string.IsNullOrEmpty (options.KeepTypeForwarderOnlyAssemblies)) + AddKeepTypeForwarderOnlyAssemblies (options.KeepTypeForwarderOnlyAssemblies); + + if (!string.IsNullOrEmpty (options.LinkSymbols)) + AddLinkSymbols (options.LinkSymbols); + + if (!string.IsNullOrEmpty (options.KeepDebugMembers)) + AddKeepDebugMembers (options.KeepDebugMembers); + + AddSkipUnresolved (options.SkipUnresolved); + + AddStripDescriptors (options.StripDescriptors); + + AddStripSubstitutions (options.StripSubstitutions); + + AddStripLinkAttributes (options.StripLinkAttributes); + + foreach (var descriptor in options.Descriptors) + AddLinkXmlFile (descriptor); + + foreach (var substitutions in options.Substitutions) + AddSubstitutions (substitutions); + + foreach (var attributeDefinition in options.LinkAttributes) + AddLinkAttributes (attributeDefinition); + + // A list of expensive optimizations which should not run by default + AddAdditionalArgument ("--disable-opt", new[] { "ipconstprop" }); + + // Unity uses different argument format and needs to be able to translate to their format. In order to make that easier + // we keep the information in flag + values format for as long as we can so that this information doesn't have to be parsed out of a single string + foreach (var additionalArgument in options.AdditionalArguments) + AddAdditionalArgument (additionalArgument.Key, additionalArgument.Value); + } + + static void AppendExpandedPaths (Dictionary dictionary, string pattern) + { + bool empty = true; + + string directoryName = Path.GetDirectoryName (pattern)!; + string searchPattern = Path.GetFileName (pattern); + + if (directoryName == "") + directoryName = "."; + + if (Directory.Exists (directoryName)) { + foreach (string fileName in Directory.EnumerateFiles (directoryName, searchPattern)) { + string fullFileName = Path.GetFullPath (fileName); + + string simpleName = Path.GetFileNameWithoutExtension (fileName); + + if (!dictionary.ContainsKey (simpleName)) { + dictionary.Add (simpleName, fullFileName); + } + + empty = false; + } + } + + if (empty) { + throw new Exception ("No files matching " + pattern); + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerTestCaseResult.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerTestCaseResult.cs new file mode 100644 index 0000000000000..8fe4bfe8b8e71 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILCompilerTestCaseResult.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Linker.Tests.TestCasesRunner; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ILCompilerTestCaseResult + { + public readonly TestCase TestCase; + public readonly NPath InputAssemblyPath; + public readonly NPath ExpectationsAssemblyPath; + public readonly TestCaseSandbox Sandbox; + public readonly TestCaseMetadataProvider MetadataProvider; + public readonly ManagedCompilationResult CompilationResult; + public readonly TestLogWriter LogWriter; + + public ILCompilerTestCaseResult (TestCase testCase, NPath inputAssemblyPath, NPath expectationsAssemblyPath, TestCaseSandbox sandbox, TestCaseMetadataProvider metadataProvider, ManagedCompilationResult compilationResult, TestLogWriter logWriter) + { + TestCase = testCase; + InputAssemblyPath = inputAssemblyPath; + ExpectationsAssemblyPath = expectationsAssemblyPath; + Sandbox = sandbox; + MetadataProvider = metadataProvider; + CompilationResult = compilationResult; + LogWriter = logWriter; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILInputCompiler.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILInputCompiler.cs new file mode 100644 index 0000000000000..32973f050fa6e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ILInputCompiler.cs @@ -0,0 +1,93 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Mono.Linker.Tests.Extensions; +using Xunit; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ILInputCompiler + { + public NPath Compile (CompilerOptions options) + { + var capturedOutput = new List (); + var process = new Process (); + SetupProcess (process, options); + process.StartInfo.RedirectStandardOutput = true; + process.OutputDataReceived += (sender, args) => capturedOutput.Add (args.Data!); + process.Start (); + process.BeginOutputReadLine (); + process.WaitForExit (); + + if (process.ExitCode != 0) { + Assert.True (false, $"Failed to compile IL assembly : {options.OutputPath}\n{capturedOutput.Aggregate ((buff, s) => buff + Environment.NewLine + s)}"); + } + + return options.OutputPath; + } + + protected virtual void SetupProcess (Process process, CompilerOptions options) + { + process.StartInfo.FileName = LocateIlasm ().ToString (); + process.StartInfo.Arguments = BuildArguments (options); + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + } + + private string BuildArguments (CompilerOptions options) + { + var args = new StringBuilder (); +#if NETCOREAPP + args.Append (options.OutputPath.ExtensionWithDot == ".dll" ? "-dll" : "-exe"); + args.Append ($" -out:{options.OutputPath.InQuotes ()}"); +#else + args.Append (options.OutputPath.ExtensionWithDot == ".dll" ? "/dll" : "/exe"); + args.Append ($" /out:{options.OutputPath.InQuotes ()}"); +#endif + args.Append ($" {options.SourceFiles.Aggregate (string.Empty, (buff, file) => $"{buff} {file.InQuotes ()}")}"); + return args.ToString (); + } + + protected virtual NPath LocateIlasm () + { +#if NETCOREAPP + var extension = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? ".exe" : ""; + + // working directory is artifacts/bin/Mono.Linker.Tests// + var toolsDir = Path.Combine (Directory.GetCurrentDirectory (), "..", "..", "..", "..", "tools"); + + var ilasmPath = Path.GetFullPath (Path.Combine (toolsDir, "ilasm", $"ilasm{extension}")).ToNPath (); + if (ilasmPath.FileExists ()) + return ilasmPath; + + throw new InvalidOperationException ("ilasm not found at " + ilasmPath); +#else + return Environment.OSVersion.Platform == PlatformID.Win32NT ? LocateIlasmOnWindows () : "ilasm".ToNPath (); +#endif + } + + public static NPath LocateIlasmOnWindows () + { + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + throw new InvalidOperationException ("This method should only be called on windows"); + + var possiblePath = RuntimeEnvironment.GetRuntimeDirectory ().ToNPath ().Combine ("ilasm.exe"); + if (possiblePath.FileExists ()) + return possiblePath; + + possiblePath = Environment.CurrentDirectory.ToNPath ().Combine ("ilasm.exe"); + if (possiblePath.FileExists ()) + return possiblePath; + + throw new InvalidOperationException ("Could not locate a ilasm.exe executable"); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/IgnoreTestException.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/IgnoreTestException.cs new file mode 100644 index 0000000000000..767bc07454fcb --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/IgnoreTestException.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + internal class IgnoreTestException : Exception + { + public IgnoreTestException (string message) : base (message) { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ManagedCompilationResult.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ManagedCompilationResult.cs new file mode 100644 index 0000000000000..fe7aa4c767da1 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ManagedCompilationResult.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Linker.Tests.Extensions; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ManagedCompilationResult + { + public ManagedCompilationResult (NPath inputAssemblyPath, NPath expectationsAssemblyPath) + { + InputAssemblyPath = inputAssemblyPath; + ExpectationsAssemblyPath = expectationsAssemblyPath; + } + + public NPath InputAssemblyPath { get; } + + public NPath ExpectationsAssemblyPath { get; } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ObjectFactory.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ObjectFactory.cs new file mode 100644 index 0000000000000..f99a06ad15062 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ObjectFactory.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Cecil; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ObjectFactory + { + public virtual TestCaseSandbox CreateSandbox (TestCase testCase) + { + return new TestCaseSandbox (testCase); + } + + public virtual TestCaseCompiler CreateCompiler (TestCaseSandbox sandbox, TestCaseCompilationMetadataProvider metadataProvider) + { + return new TestCaseCompiler (sandbox, metadataProvider); + } + + public virtual ILCompilerDriver CreateTrimmer () + { + return new ILCompilerDriver (); + } + + public virtual TestCaseMetadataProvider CreateMetadataProvider (TestCase testCase, AssemblyDefinition expectationsAssemblyDefinition) + { + return new TestCaseMetadataProvider (testCase, expectationsAssemblyDefinition); + } + + public virtual TestCaseCompilationMetadataProvider CreateCompilationMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition) + { + return new TestCaseCompilationMetadataProvider (testCase, fullTestCaseAssemblyDefinition); + } + + public virtual ILCompilerOptionsBuilder CreateTrimmerOptionsBuilder (TestCaseMetadataProvider metadataProvider) + { + return new ILCompilerOptionsBuilder (metadataProvider); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/PathUtilities.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/PathUtilities.cs new file mode 100644 index 0000000000000..5fb2090ac65e3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/PathUtilities.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; +using System.Runtime.CompilerServices; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public static class PathUtilities + { +#if NET7_0 + public const string TFMDirectoryName = "net7.0"; +#elif NET6_0 + public const string TFMDirectoryName = "net6.0"; +#elif NET5_0 + public const string TFMDirectoryName = "net5.0"; +#elif NETCOREAPP3_0 + public const string TFMDirectoryName = "netcoreapp3.0"; +#else +#error "Unknown TFM" +#endif + + public static string GetTestsSourceRootDirectory ([CallerFilePath] string? thisFile = null) => + Path.GetFullPath ((string) AppContext.GetData ("Mono.Linker.Tests.NativeAotDir")!); + + public static string GetTestAssemblyPath (string assemblyName) + { + var artifactsBinDirectory = (string) AppContext.GetData ("Mono.Linker.Tests.ArtifactsBinDir")!; + var targetArch = (string) AppContext.GetData ("Mono.Linker.Tests.TargetArchitecture")!; + var configuration = (string) AppContext.GetData ("Mono.Linker.Tests.Configuration")!; + return Path.GetFullPath (Path.Combine (artifactsBinDirectory, assemblyName, targetArch, configuration, $"{assemblyName}.dll")); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs new file mode 100644 index 0000000000000..cd3a1c2eca251 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -0,0 +1,405 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using FluentAssertions; +using ILCompiler; +using ILCompiler.Dataflow; +using ILCompiler.Logging; +using Mono.Linker.Tests.TestCasesRunner; +using Internal.TypeSystem; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Extensions; +using Xunit; +using Mono.Linker.Tests.Cases.RequiresCapability; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class ResultChecker + { + readonly BaseAssemblyResolver _originalsResolver; + readonly ReaderParameters _originalReaderParameters; + readonly ReaderParameters _linkedReaderParameters; + + public ResultChecker () + : this (new TestCaseAssemblyResolver (), + new ReaderParameters { + SymbolReaderProvider = new DefaultSymbolReaderProvider (false) + }, + new ReaderParameters { + SymbolReaderProvider = new DefaultSymbolReaderProvider (false) + }) + { + } + + public ResultChecker (BaseAssemblyResolver originalsResolver, + ReaderParameters originalReaderParameters, ReaderParameters linkedReaderParameters) + { + _originalsResolver = originalsResolver; + _originalReaderParameters = originalReaderParameters; + _linkedReaderParameters = linkedReaderParameters; + } + + public virtual void Check (ILCompilerTestCaseResult trimmedResult) + { + InitializeResolvers (trimmedResult); + + try { + var original = ResolveOriginalsAssembly (trimmedResult.ExpectationsAssemblyPath.FileNameWithoutExtension); + AdditionalChecking (trimmedResult, original); + } finally { + _originalsResolver.Dispose (); + } + } + + void InitializeResolvers (ILCompilerTestCaseResult linkedResult) + { + _originalsResolver.AddSearchDirectory (linkedResult.ExpectationsAssemblyPath.Parent.ToString ()); + } + + protected AssemblyDefinition ResolveOriginalsAssembly (string assemblyName) + { + var cleanAssemblyName = assemblyName; + if (assemblyName.EndsWith (".exe") || assemblyName.EndsWith (".dll")) + cleanAssemblyName = Path.GetFileNameWithoutExtension (assemblyName); + return _originalsResolver.Resolve (new AssemblyNameReference (cleanAssemblyName, null), _originalReaderParameters); + } + + protected virtual void AdditionalChecking (ILCompilerTestCaseResult linkResult, AssemblyDefinition original) + { + bool checkRemainingErrors = !HasAttribute (original.MainModule.GetType (linkResult.TestCase.ReconstructedFullTypeName), nameof (SkipRemainingErrorsValidationAttribute)); + VerifyLoggedMessages (original, linkResult.LogWriter, checkRemainingErrors); + } + + static bool IsProducedByNativeAOT (CustomAttribute attr) + { + var producedBy = attr.GetPropertyValue ("ProducedBy"); + return producedBy is null ? true : ((ProducedBy) producedBy).HasFlag (ProducedBy.NativeAot); + } + + static IEnumerable GetAttributeProviders (AssemblyDefinition assembly) + { + foreach (var testType in assembly.AllDefinedTypes ()) { + foreach (var provider in testType.AllMembers ()) + yield return provider; + + yield return testType; + } + + foreach (var module in assembly.Modules) + yield return module; + + yield return assembly; + } + + void VerifyLoggedMessages (AssemblyDefinition original, TestLogWriter logger, bool checkRemainingErrors) + { + List loggedMessages = logger.GetLoggedMessages (); + List<(IMemberDefinition, CustomAttribute)> expectedNoWarningsAttributes = new List<(IMemberDefinition, CustomAttribute)> (); + foreach (var attrProvider in GetAttributeProviders (original)) { + if (attrProvider.ToString() is String mystring && mystring.Contains ("RequiresInCompilerGeneratedCode/SuppressInLambda")) + Debug.WriteLine ("Print"); + foreach (var attr in attrProvider.CustomAttributes) { + if (!IsProducedByNativeAOT (attr)) + continue; + + switch (attr.AttributeType.Name) { + + case nameof (LogContainsAttribute): { + var expectedMessage = (string) attr.ConstructorArguments[0].Value; + + List matchedMessages; + if ((bool) attr.ConstructorArguments[1].Value) + matchedMessages = loggedMessages.Where (m => Regex.IsMatch (m.ToString (), expectedMessage)).ToList (); + else + matchedMessages = loggedMessages.Where (m => MessageTextContains (m.ToString (), expectedMessage)).ToList (); ; + Assert.True ( + matchedMessages.Count > 0, + $"Expected to find logged message matching `{expectedMessage}`, but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}"); + + foreach (var matchedMessage in matchedMessages) + loggedMessages.Remove (matchedMessage); + } + break; + + case nameof (LogDoesNotContainAttribute): { + var unexpectedMessage = (string) attr.ConstructorArguments[0].Value; + foreach (var loggedMessage in loggedMessages) { + var isLogged = () => { + if ((bool) attr.ConstructorArguments[1].Value) + return !Regex.IsMatch (loggedMessage.ToString (), unexpectedMessage); + return !MessageTextContains (loggedMessage.ToString (), unexpectedMessage); + }; + + Assert.True ( + isLogged (), + $"Expected to not find logged message matching `{unexpectedMessage}`, but found:{Environment.NewLine}{loggedMessage.ToString ()}{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}"); + } + } + break; + + case nameof (ExpectedWarningAttribute): { + var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0); + if (!expectedWarningCode.StartsWith ("IL")) { + Assert.Fail ($"The warning code specified in {nameof (ExpectedWarningAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'."); + } + var expectedMessageContains = ((CustomAttributeArgument[]) attr.GetConstructorArgumentValue (1)).Select (a => (string) a.Value).ToArray (); + string fileName = (string) attr.GetPropertyValue ("FileName")!; + int? sourceLine = (int?) attr.GetPropertyValue ("SourceLine"); + int? sourceColumn = (int?) attr.GetPropertyValue ("SourceColumn"); + bool? isCompilerGeneratedCode = (bool?) attr.GetPropertyValue ("CompilerGeneratedCode"); + + int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2)); + string? expectedOrigin = null; + bool expectedWarningFound = false; + + foreach (var loggedMessage in loggedMessages) { + if (loggedMessage.ToString ().Contains ("RequiresInCompilerGeneratedCode.SuppressInLambda")) { + Debug.WriteLine ("Print 2"); + } + + if (loggedMessage.Category != MessageCategory.Warning || loggedMessage.Code != expectedWarningCodeNumber) + continue; + + bool messageNotFound = false; + foreach (var expectedMessage in expectedMessageContains) { + if (!MessageTextContains (loggedMessage.Text, expectedMessage)) { + messageNotFound = true; + break; + } + } + if (messageNotFound) + continue; + + if (fileName != null) { + if (loggedMessage.Origin == null) + continue; + + var actualOrigin = loggedMessage.Origin.Value; + if (actualOrigin.FileName != null) { + // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set + if (actualOrigin.FileName.IndexOf (fileName, StringComparison.OrdinalIgnoreCase) < 0) + continue; + + if (sourceLine != null && loggedMessage.Origin?.SourceLine != sourceLine.Value) + continue; + + if (sourceColumn != null && loggedMessage.Origin?.SourceColumn != sourceColumn.Value) + continue; + } else { + // The warning was logged with member/ILoffset, so it didn't have line/column info filled + // but it will be computed from PDBs, so instead compare it in a string representation + if (expectedOrigin == null) { + expectedOrigin = fileName; + if (sourceLine.HasValue) { + expectedOrigin += "(" + sourceLine.Value; + if (sourceColumn.HasValue) + expectedOrigin += "," + sourceColumn.Value; + expectedOrigin += ")"; + } + } + + string actualOriginString = actualOrigin.ToString () ?? ""; + if (!actualOriginString.EndsWith (expectedOrigin, StringComparison.OrdinalIgnoreCase)) + continue; + } + } else if (isCompilerGeneratedCode == true) { + if (loggedMessage.Origin?.MemberDefinition is MethodDesc methodDesc) { + if (attrProvider is not IMemberDefinition expectedMember) + continue; + + string actualName = methodDesc.OwningType.ToString ().Replace("+", ".") + "." + methodDesc.Name; + if (actualName.Contains (expectedMember.DeclaringType.FullName.Replace ("/", ".")) && + actualName.Contains ("<" + expectedMember.Name + ">")) { + expectedWarningFound = true; + loggedMessages.Remove (loggedMessage); + break; + } + if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && + actualName.Contains (".cctor") && (expectedMember is FieldDefinition || expectedMember is PropertyDefinition)) { + expectedWarningFound = true; + loggedMessages.Remove (loggedMessage); + break; + } + if (methodDesc.Name == ".ctor" && + methodDesc.OwningType.ToString () == expectedMember.FullName) { + expectedWarningFound = true; + loggedMessages.Remove (loggedMessage); + break; + } + } + continue; + } else { + if (LogMessageHasSameOriginMember (loggedMessage, attrProvider)) { + expectedWarningFound = true; + loggedMessages.Remove (loggedMessage); + break; + } + continue; + } + + expectedWarningFound = true; + loggedMessages.Remove (loggedMessage); + break; + } + + var expectedOriginString = fileName == null + ? GetExpectedOriginDisplayName (attrProvider) + ": " + : ""; + + Assert.True (expectedWarningFound, + $"Expected to find warning: {(fileName != null ? fileName + (sourceLine != null ? $"({sourceLine},{sourceColumn})" : "") + ": " : "")}" + + $"warning {expectedWarningCode}: {expectedOriginString}" + + $"and message containing {string.Join (" ", expectedMessageContains.Select (m => "'" + m + "'"))}, " + + $"but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}"); + } + break; + + case nameof (ExpectedNoWarningsAttribute): + // Postpone processing of negative checks, to make it possible to mark some warnings as expected (will be removed from the list above) + // and then do the negative check on the rest. + var memberDefinition = attrProvider as IMemberDefinition; + Assert.NotNull (memberDefinition); + expectedNoWarningsAttributes.Add ((memberDefinition, attr)); + break; + } + } + } + + foreach ((var attrProvider, var attr) in expectedNoWarningsAttributes) { + var unexpectedWarningCode = attr.ConstructorArguments.Count == 0 ? null : (string) attr.GetConstructorArgumentValue (0); + if (unexpectedWarningCode != null && !unexpectedWarningCode.StartsWith ("IL")) { + Assert.Fail ($"The warning code specified in ExpectedNoWarnings attribute must start with the 'IL' prefix. Specified value: '{unexpectedWarningCode}'."); + } + + int? unexpectedWarningCodeNumber = unexpectedWarningCode == null ? null : int.Parse (unexpectedWarningCode.Substring (2)); + + MessageContainer? unexpectedWarningMessage = null; + foreach (var mc in logger.GetLoggedMessages ()) { + if (mc.Category != MessageCategory.Warning) + continue; + + if (unexpectedWarningCodeNumber != null && unexpectedWarningCodeNumber.Value != mc.Code) + continue; + + // This is a hacky way to say anything in the "subtree" of the attrProvider + if ((mc.Origin?.MemberDefinition is TypeSystemEntity member) && member.ToString ()?.Contains (attrProvider.FullName) != true) + continue; + + unexpectedWarningMessage = mc; + break; + } + + Assert.False (unexpectedWarningMessage.HasValue, + $"Unexpected warning found: {unexpectedWarningMessage}"); + } + + if (checkRemainingErrors) { + var remainingErrors = loggedMessages.Where (m => Regex.IsMatch (m.ToString (), @".*(error | warning): \d{4}.*")); + Assert.False (remainingErrors.Any (), $"Found unexpected errors:{Environment.NewLine}{string.Join (Environment.NewLine, remainingErrors)}"); + } + + bool LogMessageHasSameOriginMember (MessageContainer mc, ICustomAttributeProvider expectedOriginProvider) + { + var origin = mc.Origin; + Debug.Assert (origin != null); + if (GetActualOriginDisplayName (origin?.MemberDefinition) == ConvertSignatureToIlcFormat (GetExpectedOriginDisplayName (expectedOriginProvider))) + return true; + + var actualMember = origin!.Value.MemberDefinition; + // Compensate for cases where for some reason the OM doesn't preserve the declaring types + // on certain things after trimming. + if (actualMember != null && GetOwningType (actualMember) == null && + GetMemberName (actualMember) == (expectedOriginProvider as IMemberDefinition)?.Name) + return true; + + return false; + } + + static TypeDesc? GetOwningType (TypeSystemEntity entity) => entity switch { + DefType defType => defType.ContainingType, + MethodDesc method => method.OwningType, + FieldDesc field => field.OwningType, + _ => null + }; + + static string? GetMemberName (TypeSystemEntity? entity) => entity switch { + DefType defType => defType.Name, + MethodDesc method => method.Name, + FieldDesc field => field.Name, + _ => null + }; + + static string? GetActualOriginDisplayName (TypeSystemEntity? entity) => entity switch { + DefType defType => TrimAssemblyNamePrefix (defType.ToString ()), + MethodDesc method => TrimAssemblyNamePrefix (method.GetDisplayName ()), + FieldDesc field => TrimAssemblyNamePrefix (field.ToString ()), + ModuleDesc module => module.Assembly.GetName ().Name, + _ => null + }; + + static string TrimAssemblyNamePrefix (string name) + { + if (name.StartsWith ('[')) { + int i = name.IndexOf (']'); + if (i > 0) { + return name.Substring (i + 1); + } + } + + return name; + } + + static string GetExpectedOriginDisplayName (ICustomAttributeProvider provider) => + provider switch { + MethodDefinition method => method.GetDisplayName (), + FieldDefinition field => field.GetDisplayName (), + IMemberDefinition member => member.FullName, + AssemblyDefinition asm => asm.Name.Name, + _ => throw new NotImplementedException () + }; + + static bool MessageTextContains (string message, string value) + { + // This is a workaround for different formatting of methods between ilc and linker/analyzer + // Sometimes they're written with a space after comma and sometimes without + // Method(String,String) - ilc + // Method(String, String) - linker/analyzer + return message.Contains (value) || message.Contains (ConvertSignatureToIlcFormat (value)); + } + + static string ConvertSignatureToIlcFormat (string value) + { + if (value.Contains ('(') || value.Contains ('<')) { + value = value.Replace (", ", ","); + } + + return value; + } + } + + static bool HasAttribute (ICustomAttributeProvider caProvider, string attributeName) + { + if (caProvider is AssemblyDefinition assembly && assembly.EntryPoint != null) + return assembly.EntryPoint.DeclaringType.CustomAttributes + .Any (attr => attr.AttributeType.Name == attributeName); + + if (caProvider is TypeDefinition type) + return type.CustomAttributes.Any (attr => attr.AttributeType.Name == attributeName); + + return false; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs new file mode 100644 index 0000000000000..37883af7d3bda --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Linker.Tests.Extensions; + +#nullable disable + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class SetupCompileInfo + { + public string OutputName; + public NPath[] SourceFiles; + public string[] Defines; + public string[] References; + public SourceAndDestinationPair[] Resources; + public string AdditionalArguments; + public string CompilerToUse; + public bool AddAsReference; + public bool RemoveFromLinkerInput; + public string OutputSubFolder; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SourceAndDestinationPair.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SourceAndDestinationPair.cs new file mode 100644 index 0000000000000..52d333d9caf6a --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/SourceAndDestinationPair.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Linker.Tests.Extensions; + +#nullable disable + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class SourceAndDestinationPair + { + public NPath Source; + public string DestinationFileName; + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseAssemblyResolver.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseAssemblyResolver.cs new file mode 100644 index 0000000000000..dec3270905e44 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseAssemblyResolver.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Mono.Cecil; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseAssemblyResolver : DefaultAssemblyResolver + { + readonly HashSet itemsToDispose; + + public TestCaseAssemblyResolver () + { + itemsToDispose = new HashSet (); + } + + public override AssemblyDefinition? Resolve (AssemblyNameReference name, ReaderParameters parameters) + { + var assembly = base.Resolve (name, parameters); + + if (assembly == null) + return null; + + // Don't do any caching because the reader parameters could be different each time + // but we still want to track items that need to be disposed for easy clean up + itemsToDispose.Add (assembly); + + if (assembly.MainModule.SymbolReader != null) + itemsToDispose.Add (assembly.MainModule.SymbolReader); + return assembly; + } + + protected override void Dispose (bool disposing) + { + foreach (var item in itemsToDispose) + item.Dispose (); + + base.Dispose (disposing); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCollector.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCollector.cs new file mode 100644 index 0000000000000..1f9fe04d70e11 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCollector.cs @@ -0,0 +1,165 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.Cecil; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseCollector + { + private readonly NPath _rootDirectory; + private readonly NPath _testCaseAssemblyPath; + + public TestCaseCollector (string rootDirectory, string testCaseAssemblyPath) + : this (rootDirectory.ToNPath (), testCaseAssemblyPath.ToNPath ()) + { + } + + public TestCaseCollector (NPath rootDirectory, NPath testCaseAssemblyPath) + { + _rootDirectory = rootDirectory; + _testCaseAssemblyPath = testCaseAssemblyPath; + } + + public IEnumerable Collect () + { + return Collect (AllSourceFiles ()); + } + + public TestCase? Collect (NPath sourceFile) + { + return Collect (new[] { sourceFile }).FirstOrDefault (); + } + + public IEnumerable Collect (IEnumerable sourceFiles) + { + _rootDirectory.DirectoryMustExist (); + _testCaseAssemblyPath.FileMustExist (); + + using (var caseAssemblyDefinition = AssemblyDefinition.ReadAssembly (_testCaseAssemblyPath.ToString ())) { + foreach (var file in sourceFiles) { + if (CreateCase (caseAssemblyDefinition, file, out TestCase? testCase) && testCase != null) + yield return testCase; + } + } + } + + public IEnumerable AllSourceFiles () + { + _rootDirectory.DirectoryMustExist (); + + foreach (var file in _rootDirectory.Files ("*.cs")) { + yield return file; + } + + foreach (var subDir in _rootDirectory.Directories ()) { + if (subDir.FileName == "bin" || subDir.FileName == "obj" || subDir.FileName == "Properties") + continue; + + foreach (var file in subDir.Files ("*.cs", true)) { + + var relativeParents = file.RelativeTo (_rootDirectory); + // Magic : Anything in a directory named Dependencies is assumed to be a dependency to a test case + // and never a test itself + // This makes life a little easier when writing these supporting files as it removes some constraints you would previously have + // had to follow such as ensuring a class exists that matches the file name and putting [NotATestCase] on that class + if (relativeParents.RecursiveParents.Any (p => p.Elements.Any () && p.FileName == "Dependencies")) + continue; + + // Magic: Anything in a directory named Individual is expected to be ran by it's own [Test] rather than as part of [TestCaseSource] + if (relativeParents.RecursiveParents.Any (p => p.Elements.Any () && p.FileName == "Individual")) + continue; + + yield return file; + } + } + } + + public TestCase? CreateIndividualCase (Type testCaseType) + { + _rootDirectory.DirectoryMustExist (); + _testCaseAssemblyPath.FileMustExist (); + + var pathRelativeToAssembly = $"{testCaseType.FullName?.Substring (testCaseType.Module.Name.Length - 3).Replace ('.', '/')}.cs"; + var fullSourcePath = _rootDirectory.Combine (pathRelativeToAssembly).FileMustExist (); + + using (var caseAssemblyDefinition = AssemblyDefinition.ReadAssembly (_testCaseAssemblyPath.ToString ())) { + if (!CreateCase (caseAssemblyDefinition, fullSourcePath, out TestCase? testCase)) + throw new ArgumentException ($"Could not create a test case for `{testCaseType}`. Ensure the namespace matches it's location on disk"); + + return testCase; + } + } + + private bool CreateCase (AssemblyDefinition caseAssemblyDefinition, NPath sourceFile, out TestCase? testCase) + { + var potentialCase = new TestCase (sourceFile, _rootDirectory, _testCaseAssemblyPath); + + var typeDefinition = FindTypeDefinition (caseAssemblyDefinition, potentialCase); + + testCase = null; + + if (typeDefinition == null) { + Console.WriteLine ($"Could not find the matching type for test case {sourceFile}. Ensure the file name and class name match"); + return false; + } + + if (typeDefinition.HasAttribute (nameof (NotATestCaseAttribute))) { + return false; + } + + // Verify the class as a static main method + var mainMethod = typeDefinition.Methods.FirstOrDefault (m => m.Name == "Main"); + + if (mainMethod == null) { + Console.WriteLine ($"{typeDefinition} in {sourceFile} is missing a Main() method"); + return false; + } + + if (!mainMethod.IsStatic) { + Console.WriteLine ($"The Main() method for {typeDefinition} in {sourceFile} should be static"); + return false; + } + + testCase = potentialCase; + return true; + } + + private static TypeDefinition? FindTypeDefinition (AssemblyDefinition caseAssemblyDefinition, TestCase testCase) + { + var typeDefinition = caseAssemblyDefinition.MainModule.GetType (testCase.ReconstructedFullTypeName); + + // For all of the Test Cases, the full type name we constructed from the directory structure will be correct and we can successfully find + // the type from GetType. + if (typeDefinition != null) + return typeDefinition; + + // However, some of types are supporting types rather than test cases. and may not follow the standardized naming scheme of the test cases + // We still need to be able to locate these type defs so that we can parse some of the metadata on them. + // One example, Unity run's into this with it's tests that require a type UnityEngine.MonoBehaviours to exist. This tpe is defined in it's own + // file and it cannot follow our standardized naming directory & namespace naming scheme since the namespace must be UnityEngine + foreach (var type in caseAssemblyDefinition.MainModule.Types) { + // Let's assume we should never have to search for a test case that has no namespace. If we don't find the type from GetType, then o well, that's not a test case. + if (string.IsNullOrEmpty (type.Namespace)) + continue; + + if (type.Name == testCase.Name) { + // This isn't foolproof, but let's do a little extra vetting to make sure the type we found corresponds to the source file we are + // processing. + if (!testCase.SourceFile.ReadAllText ().Contains ($"namespace {type.Namespace}")) + continue; + + return type; + } + } + + return null; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompilationMetadataProvider.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompilationMetadataProvider.cs new file mode 100644 index 0000000000000..1aa354f58176b --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompilationMetadataProvider.cs @@ -0,0 +1,242 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseCompilationMetadataProvider : BaseMetadataProvider + { + + public TestCaseCompilationMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition) + : base (testCase, fullTestCaseAssemblyDefinition) + { + + } + + public virtual TestRunCharacteristics Characteristics => + TestRunCharacteristics.TargetingNetCore | TestRunCharacteristics.SupportsDefaultInterfaceMethods | TestRunCharacteristics.SupportsStaticInterfaceMethods; + + public virtual bool IsIgnored ([NotNullWhen(true)] out string? reason) + { + var ignoreAttribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (IgnoreTestCaseAttribute)); + if (ignoreAttribute != null) { + if (ignoreAttribute.ConstructorArguments.Count == 1) { + reason = (string) ignoreAttribute.ConstructorArguments.First ().Value; + return true; + } else { + throw new ArgumentException ($"Unhandled {nameof (IgnoreTestCaseAttribute)} constructor with {ignoreAttribute.ConstructorArguments} arguments"); + } + } + + var requirementsAttribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (TestCaseRequirementsAttribute)); + if (requirementsAttribute != null) { + if (requirementsAttribute.ConstructorArguments.Count == 2) { + var testCaseRequirements = (TestRunCharacteristics) requirementsAttribute.ConstructorArguments[0].Value; + + foreach (var value in Enum.GetValues (typeof (TestRunCharacteristics))) { + if (IsRequirementMissing ((TestRunCharacteristics) value, testCaseRequirements)) { + reason = (string) requirementsAttribute.ConstructorArguments[1].Value; + return true; + } + } + } else { + throw new ArgumentException ($"Unhandled {nameof (TestCaseRequirementsAttribute)} constructor with {requirementsAttribute.ConstructorArguments} arguments"); + } + } + + reason = null; + return false; + } + + bool IsRequirementMissing (TestRunCharacteristics requirement, TestRunCharacteristics testCaseRequirements) + { + return testCaseRequirements.HasFlag (requirement) && !Characteristics.HasFlag (requirement); + } + + public virtual IEnumerable GetDefines () + { + // There are a few tests related to native pdbs where the assertions are different between windows and non-windows + // To enable test cases to define different expected behavior we set this special define + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + yield return "WIN32"; + + if (Characteristics.HasFlag (TestRunCharacteristics.TargetingNetCore)) + yield return "NETCOREAPP"; + + if (Characteristics.HasFlag (TestRunCharacteristics.SupportsDefaultInterfaceMethods)) + yield return "SUPPORTS_DEFAULT_INTERFACE_METHODS"; + + foreach (var attr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (DefineAttribute))) + yield return (string) attr.ConstructorArguments.First ().Value; + } + + public virtual string GetAssemblyName () + { + var asLibraryAttribute = _testCaseTypeDefinition.CustomAttributes + .FirstOrDefault (attr => attr.AttributeType.Name == nameof (SetupCompileAsLibraryAttribute)); + var defaultName = asLibraryAttribute == null ? "test.exe" : "test.dll"; + return GetOptionAttributeValue (nameof (SetupCompileAssemblyNameAttribute), defaultName)!; + } + + public virtual string GetCSharpCompilerToUse () + { + return GetOptionAttributeValue (nameof (SetupCSharpCompilerToUseAttribute), string.Empty)!.ToLower (); + } + + public virtual IEnumerable GetSetupCompilerArguments () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupCompileArgumentAttribute)) + .Select (attr => (string) attr.ConstructorArguments.First ().Value); + } + + public virtual IEnumerable AdditionalFilesToSandbox () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SandboxDependencyAttribute)) + .Select (GetSourceAndRelativeDestinationValue); + } + + static string GetReferenceDir () + { + string runtimeDir = Path.GetDirectoryName (typeof (object).Assembly.Location)!; + string ncaVersion = Path.GetFileName (runtimeDir); + string dotnetDir = Path.GetDirectoryName (Path.GetDirectoryName (Path.GetDirectoryName (runtimeDir)))!; + return Path.Combine (dotnetDir, "packs", "Microsoft.NETCore.App.Ref", ncaVersion, "ref", PathUtilities.TFMDirectoryName); + } + + public virtual IEnumerable GetCommonReferencedAssemblies (NPath workingDirectory) + { + yield return workingDirectory.Combine ("Mono.Linker.Tests.Cases.Expectations.dll").ToString (); + if (Characteristics.HasFlag (TestRunCharacteristics.TargetingNetCore)) { + string referenceDir = GetReferenceDir (); + + yield return Path.Combine (referenceDir, "mscorlib.dll"); + yield return Path.Combine (referenceDir, "System.Collections.dll"); + yield return Path.Combine (referenceDir, "System.ComponentModel.TypeConverter.dll"); + yield return Path.Combine (referenceDir, "System.Console.dll"); + yield return Path.Combine (referenceDir, "System.Linq.Expressions.dll"); + yield return Path.Combine (referenceDir, "System.ObjectModel.dll"); + yield return Path.Combine (referenceDir, "System.Runtime.dll"); + yield return Path.Combine (referenceDir, "System.Runtime.Extensions.dll"); + yield return Path.Combine (referenceDir, "System.Runtime.InteropServices.dll"); + } else { + yield return "mscorlib.dll"; + } + } + + public virtual IEnumerable GetReferencedAssemblies (NPath workingDirectory) + { + foreach (var fileName in GetReferenceValues ()) { + + if (fileName.StartsWith ("System.", StringComparison.Ordinal) || fileName.StartsWith ("Mono.", StringComparison.Ordinal) || fileName.StartsWith ("Microsoft.", StringComparison.Ordinal)) { + if (Characteristics.HasFlag (TestRunCharacteristics.TargetingNetCore)) { + var referenceDir = GetReferenceDir (); + var filePath = Path.Combine (referenceDir, fileName); + + if (File.Exists (filePath)) { + yield return filePath; + } else { + yield return fileName; + } + } else { + yield return fileName; + } + } else { + // Drop any relative path information. Sandboxing will have taken care of copying the reference to the directory + yield return workingDirectory.Combine (Path.GetFileName (fileName)); + } + } + } + + public virtual IEnumerable GetReferenceDependencies () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (ReferenceDependencyAttribute)) + .Select (attr => (string) attr.ConstructorArguments[0].Value); + } + + public virtual IEnumerable GetReferenceValues () + { + foreach (var referenceAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (ReferenceAttribute))) + yield return (string) referenceAttr.ConstructorArguments.First ().Value; + } + + public virtual IEnumerable GetResources () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupCompileResourceAttribute)) + .Select (GetSourceAndRelativeDestinationValue); + } + + public virtual IEnumerable GetSetupCompileAssembliesBefore () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupCompileBeforeAttribute)) + .Select (CreateSetupCompileAssemblyInfo); + } + + public virtual IEnumerable GetSetupCompileAssembliesAfter () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupCompileAfterAttribute)) + .Select (CreateSetupCompileAssemblyInfo); + } + + private SetupCompileInfo CreateSetupCompileAssemblyInfo (CustomAttribute attribute) + { + var ctorArguments = attribute.ConstructorArguments; + return new SetupCompileInfo { + OutputName = (string) ctorArguments[0].Value, + SourceFiles = SourceFilesForAttributeArgument (ctorArguments[1]), + References = ((CustomAttributeArgument[]) ctorArguments[2].Value)?.Select (arg => arg.Value.ToString ()).ToArray (), + Defines = ((CustomAttributeArgument[]) ctorArguments[3].Value)?.Select (arg => arg.Value.ToString ()).ToArray (), + Resources = ResourcesForAttributeArgument (ctorArguments[4]), + AdditionalArguments = (string) ctorArguments[5].Value, + CompilerToUse = (string) ctorArguments[6].Value, + AddAsReference = ctorArguments.Count >= 8 ? (bool) ctorArguments[7].Value : true, + RemoveFromLinkerInput = ctorArguments.Count >= 9 ? (bool) ctorArguments[8].Value : false, + OutputSubFolder = ctorArguments.Count >= 10 ? (string) ctorArguments[9].Value : null + }; + } + + protected NPath[] SourceFilesForAttributeArgument (CustomAttributeArgument attributeArgument) + { + return ((CustomAttributeArgument[]) attributeArgument.Value) + .Select (attributeArg => SourceFileForAttributeArgumentValue (attributeArg.Value)) + .Distinct () + .ToArray (); + } + + protected SourceAndDestinationPair[]? ResourcesForAttributeArgument (CustomAttributeArgument attributeArgument) + { + return ((CustomAttributeArgument[]) attributeArgument.Value) + ?.Select (arg => { + var referenceArg = (CustomAttributeArgument) arg.Value; + if (referenceArg.Value is string source) { + var fullSource = MakeSourceTreeFilePathAbsolute (source); + return new SourceAndDestinationPair { + Source = fullSource, + DestinationFileName = fullSource.FileName + }; + } + var sourceAndDestination = (CustomAttributeArgument[]) referenceArg.Value; + return new SourceAndDestinationPair { + Source = MakeSourceTreeFilePathAbsolute (sourceAndDestination[0].Value!.ToString ()!), + DestinationFileName = sourceAndDestination[1].Value!.ToString ()! + }; + }) + ?.ToArray (); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs new file mode 100644 index 0000000000000..3f47904efa69e --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs @@ -0,0 +1,411 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using Mono.Linker.Tests.Extensions; +using Xunit; +#if NETCOREAPP +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.CSharp; +#endif + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseCompiler + { + protected readonly TestCaseCompilationMetadataProvider _metadataProvider; + protected readonly TestCaseSandbox _sandbox; + protected readonly ILInputCompiler _ilCompiler; + + public TestCaseCompiler (TestCaseSandbox sandbox, TestCaseCompilationMetadataProvider metadataProvider) + : this (sandbox, metadataProvider, new ILInputCompiler ()) + { + } + + public TestCaseCompiler (TestCaseSandbox sandbox, TestCaseCompilationMetadataProvider metadataProvider, ILInputCompiler ilCompiler) + { + _ilCompiler = ilCompiler; + _sandbox = sandbox; + _metadataProvider = metadataProvider; + } + + public NPath CompileTestIn (NPath outputDirectory, string outputName, IEnumerable sourceFiles, string[] commonReferences, string[] mainAssemblyReferences, IEnumerable? defines, NPath[] resources, string[] additionalArguments) + { + var originalCommonReferences = commonReferences.Select (r => r.ToNPath ()).ToArray (); + var originalDefines = defines?.ToArray () ?? new string[0]; + + Prepare (outputDirectory); + + var removeFromLinkerInputAssemblies = new List (); + var compiledReferences = CompileBeforeTestCaseAssemblies (outputDirectory, originalCommonReferences, originalDefines, removeFromLinkerInputAssemblies).ToArray (); + var allTestCaseReferences = originalCommonReferences + .Concat (compiledReferences) + .Concat (mainAssemblyReferences.Select (r => r.ToNPath ())) + .ToArray (); + + var options = CreateOptionsForTestCase ( + outputDirectory.Combine (outputName), + sourceFiles.Select (s => s.ToNPath ()).ToArray (), + allTestCaseReferences, + originalDefines, + resources, + additionalArguments); + var testAssembly = CompileAssembly (options); + + + // The compile after step is used by tests to mess around with the input to the linker. Generally speaking, it doesn't seem like we would ever want to mess with the + // expectations assemblies because this would undermine our ability to inspect them for expected results during ResultChecking. The UnityLinker UnresolvedHandling tests depend on this + // behavior of skipping the after test compile + if (outputDirectory != _sandbox.ExpectationsDirectory) { + CompileAfterTestCaseAssemblies (outputDirectory, originalCommonReferences, originalDefines, removeFromLinkerInputAssemblies); + + foreach (var assemblyToRemove in removeFromLinkerInputAssemblies) + assemblyToRemove.DeleteIfExists (); + } + + return testAssembly; + } + + protected virtual void Prepare (NPath outputDirectory) + { + } + + protected virtual CompilerOptions CreateOptionsForTestCase (NPath outputPath, NPath[] sourceFiles, NPath[] references, string[] defines, NPath[] resources, string[] additionalArguments) + { + return new CompilerOptions { + OutputPath = outputPath, + SourceFiles = sourceFiles, + References = references, + Defines = defines.Concat (_metadataProvider.GetDefines ()).ToArray (), + Resources = resources, + AdditionalArguments = additionalArguments, + CompilerToUse = _metadataProvider.GetCSharpCompilerToUse () + }; + } + + protected virtual CompilerOptions CreateOptionsForSupportingAssembly (SetupCompileInfo setupCompileInfo, NPath outputDirectory, NPath[] sourceFiles, NPath[] references, string[] defines, NPath[] resources) + { + var allDefines = defines.Concat (setupCompileInfo.Defines ?? new string[0]).ToArray (); + var allReferences = references.Concat (setupCompileInfo.References?.Select (p => MakeSupportingAssemblyReferencePathAbsolute (outputDirectory, p)) ?? new NPath[0]).ToArray (); + string[]? additionalArguments = string.IsNullOrEmpty (setupCompileInfo.AdditionalArguments) ? null : new[] { setupCompileInfo.AdditionalArguments }; + return new CompilerOptions { + OutputPath = outputDirectory.Combine (setupCompileInfo.OutputName), + SourceFiles = sourceFiles, + References = allReferences, + Defines = allDefines, + Resources = resources, + AdditionalArguments = additionalArguments, + CompilerToUse = setupCompileInfo.CompilerToUse?.ToLower () + }; + } + + private IEnumerable CompileBeforeTestCaseAssemblies (NPath outputDirectory, NPath[] references, string[] defines, IList removeFromLinkerInputAssemblies) + { + foreach (var setupCompileInfo in _metadataProvider.GetSetupCompileAssembliesBefore ()) { + NPath outputFolder; + if (setupCompileInfo.OutputSubFolder == null) { + outputFolder = outputDirectory; + } else { + outputFolder = outputDirectory.Combine (setupCompileInfo.OutputSubFolder); + Directory.CreateDirectory (outputFolder.ToString ()); + } + + var options = CreateOptionsForSupportingAssembly ( + setupCompileInfo, + outputFolder, + CollectSetupBeforeSourcesFiles (setupCompileInfo), + references, + defines, + CollectSetupBeforeResourcesFiles (setupCompileInfo)); + var output = CompileAssembly (options); + + if (setupCompileInfo.RemoveFromLinkerInput) + removeFromLinkerInputAssemblies.Add (output); + + if (setupCompileInfo.AddAsReference) + yield return output; + } + } + + private void CompileAfterTestCaseAssemblies (NPath outputDirectory, NPath[] references, string[] defines, IList removeFromLinkerInputAssemblies) + { + foreach (var setupCompileInfo in _metadataProvider.GetSetupCompileAssembliesAfter ()) { + var options = CreateOptionsForSupportingAssembly ( + setupCompileInfo, + outputDirectory, + CollectSetupAfterSourcesFiles (setupCompileInfo), + references, + defines, + CollectSetupAfterResourcesFiles (setupCompileInfo)); + var output = CompileAssembly (options); + + if (setupCompileInfo.RemoveFromLinkerInput) + removeFromLinkerInputAssemblies.Add (output); + } + } + + private NPath[] CollectSetupBeforeSourcesFiles (SetupCompileInfo info) + { + return CollectSourceFilesFrom (_sandbox.BeforeReferenceSourceDirectoryFor (info.OutputName)); + } + + private NPath[] CollectSetupAfterSourcesFiles (SetupCompileInfo info) + { + return CollectSourceFilesFrom (_sandbox.AfterReferenceSourceDirectoryFor (info.OutputName)); + } + + private NPath[] CollectSetupBeforeResourcesFiles (SetupCompileInfo info) + { + return _sandbox.BeforeReferenceResourceDirectoryFor (info.OutputName).Files ().ToArray (); + } + + private NPath[] CollectSetupAfterResourcesFiles (SetupCompileInfo info) + { + return _sandbox.AfterReferenceResourceDirectoryFor (info.OutputName).Files ().ToArray (); + } + + private static NPath[] CollectSourceFilesFrom (NPath directory) + { + var sourceFiles = directory.Files ("*.cs").ToArray (); + if (sourceFiles.Length > 0) + return sourceFiles; + + sourceFiles = directory.Files ("*.il").ToArray (); + if (sourceFiles.Length > 0) + return sourceFiles; + + throw new FileNotFoundException ($"Didn't find any sources files in {directory}"); + } + + protected static NPath MakeSupportingAssemblyReferencePathAbsolute (NPath outputDirectory, string referenceFileName) + { + // Not a good idea to use a full path in a test, but maybe someone is trying to quickly test something locally + if (Path.IsPathRooted (referenceFileName)) + return referenceFileName.ToNPath (); + +#if NETCOREAPP + if (referenceFileName.StartsWith ("System.", StringComparison.Ordinal) || + referenceFileName.StartsWith ("Mono.", StringComparison.Ordinal) || + referenceFileName.StartsWith ("Microsoft.", StringComparison.Ordinal) || + referenceFileName == "netstandard.dll") { + + var frameworkDir = Path.GetFullPath (Path.GetDirectoryName (typeof (object).Assembly.Location)!); + var filePath = Path.Combine (frameworkDir, referenceFileName); + + if (File.Exists (filePath)) + return filePath.ToNPath (); + } +#endif + + var possiblePath = outputDirectory.Combine (referenceFileName); + if (possiblePath.FileExists ()) + return possiblePath; + + return referenceFileName.ToNPath (); + } + + protected NPath CompileAssembly (CompilerOptions options) + { + if (options.SourceFiles.Any (path => path.ExtensionWithDot == ".cs")) + return CompileCSharpAssembly (options); + + if (options.SourceFiles.Any (path => path.ExtensionWithDot == ".il")) + return CompileIlAssembly (options); + + throw new NotSupportedException ($"Unable to compile sources files with extension `{options.SourceFiles.First ().ExtensionWithDot}`"); + } + + protected virtual NPath CompileCSharpAssemblyWithDefaultCompiler (CompilerOptions options) + { +#if NETCOREAPP + return CompileCSharpAssemblyWithRoslyn (options); +#else + return CompileCSharpAssemblyWithCsc (options); +#endif + } + +#if NETCOREAPP + protected virtual NPath CompileCSharpAssemblyWithRoslyn (CompilerOptions options) + { + var languageVersion = LanguageVersion.Default; + var compilationOptions = new CSharpCompilationOptions ( + outputKind: options.OutputPath.FileName.EndsWith (".exe") ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary, + assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default + ); + // Default debug info format for the current platform. + DebugInformationFormat debugType = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; + bool emitPdb = false; + if (options.AdditionalArguments != null) { + foreach (var option in options.AdditionalArguments) { + switch (option) { + case "/unsafe": + compilationOptions = compilationOptions.WithAllowUnsafe (true); + break; + case "/optimize+": + compilationOptions = compilationOptions.WithOptimizationLevel (OptimizationLevel.Release); + break; + case "/debug:full": + case "/debug:pdbonly": + // Use platform's default debug info. This behavior is the same as csc. + emitPdb = true; + break; + case "/debug:portable": + emitPdb = true; + debugType = DebugInformationFormat.PortablePdb; + break; + case "/debug:embedded": + emitPdb = true; + debugType = DebugInformationFormat.Embedded; + break; + case "/langversion:7.3": + languageVersion = LanguageVersion.CSharp7_3; + break; + + } + } + } + var parseOptions = new CSharpParseOptions (preprocessorSymbols: options.Defines, languageVersion: languageVersion); + var emitOptions = new EmitOptions (debugInformationFormat: debugType); + var pdbPath = (!emitPdb || debugType == DebugInformationFormat.Embedded) ? null : options.OutputPath.ChangeExtension (".pdb").ToString (); + + var syntaxTrees = options.SourceFiles.Select (p => + CSharpSyntaxTree.ParseText ( + text: p.ReadAllText (), + options: parseOptions + ) + ); + + var compilation = CSharpCompilation.Create ( + assemblyName: options.OutputPath.FileNameWithoutExtension, + syntaxTrees: syntaxTrees, + references: options.References.Select (r => MetadataReference.CreateFromFile (r)), + options: compilationOptions + ); + + var manifestResources = options.Resources.Select (r => { + var fullPath = r.ToString (); + return new ResourceDescription ( + resourceName: Path.GetFileName (fullPath), + dataProvider: () => new FileStream (fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), + isPublic: true + ); + }); + + EmitResult result; + using (var outputStream = File.Create (options.OutputPath.ToString ())) + using (var pdbStream = pdbPath == null ? null : File.Create (pdbPath)) { + result = compilation.Emit ( + peStream: outputStream, + pdbStream: pdbStream, + manifestResources: manifestResources, + options: emitOptions + ); + } + + var errors = new StringBuilder (); + if (result.Success) + return options.OutputPath; + + foreach (var diagnostic in result.Diagnostics) + errors.AppendLine (diagnostic.ToString ()); + throw new Exception ("Roslyn compilation errors: " + errors); + } +#endif + + protected virtual NPath CompileCSharpAssemblyWithCsc (CompilerOptions options) + { +#if NETCOREAPP + return CompileCSharpAssemblyWithRoslyn (options); +#else + return CompileCSharpAssemblyWithExternalCompiler (LocateCscExecutable (), options, "/shared "); +#endif + } + + protected virtual NPath CompileCSharpAssemblyWithMcs (CompilerOptions options) + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + CompileCSharpAssemblyWithExternalCompiler (LocateMcsExecutable (), options, string.Empty); + + return CompileCSharpAssemblyWithDefaultCompiler (options); + } + + protected NPath CompileCSharpAssemblyWithExternalCompiler (string executable, CompilerOptions options, string compilerSpecificArguments) + { + var capturedOutput = new List (); + var process = new Process (); + process.StartInfo.FileName = executable; + process.StartInfo.Arguments = OptionsToCompilerCommandLineArguments (options, compilerSpecificArguments); + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + process.StartInfo.RedirectStandardOutput = true; + process.OutputDataReceived += (sender, args) => capturedOutput.Add (args.Data!); + process.Start (); + process.BeginOutputReadLine (); + process.WaitForExit (); + + if (process.ExitCode != 0) + Assert.True (false, $"Failed to compile assembly with csc: {options.OutputPath}\n{capturedOutput.Aggregate ((buff, s) => buff + Environment.NewLine + s)}"); + + return options.OutputPath; + } + + static string LocateMcsExecutable () + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + throw new IgnoreTestException ("We don't have a universal way of locating mcs on Windows"); + + return "mcs"; + } + + protected string OptionsToCompilerCommandLineArguments (CompilerOptions options, string compilerSpecificArguments) + { + var builder = new StringBuilder (); + if (!string.IsNullOrEmpty (compilerSpecificArguments)) + builder.Append (compilerSpecificArguments); + builder.Append ($"/out:{options.OutputPath}"); + var target = options.OutputPath.ExtensionWithDot == ".exe" ? "exe" : "library"; + builder.Append ($" /target:{target}"); + if (options.Defines != null && options.Defines.Length > 0) + builder.Append (options.Defines.Aggregate (string.Empty, (buff, arg) => $"{buff} /define:{arg}")); + + builder.Append (options.References.Aggregate (string.Empty, (buff, arg) => $"{buff} /r:{arg}")); + + if (options.Resources != null && options.Resources.Length > 0) + builder.Append (options.Resources.Aggregate (string.Empty, (buff, arg) => $"{buff} /res:{arg}")); + + if (options.AdditionalArguments != null && options.AdditionalArguments.Length > 0) + builder.Append (options.AdditionalArguments.Aggregate (string.Empty, (buff, arg) => $"{buff} {arg}")); + + builder.Append (options.SourceFiles.Aggregate (string.Empty, (buff, arg) => $"{buff} {arg}")); + + return builder.ToString (); + } + + protected NPath CompileCSharpAssembly (CompilerOptions options) + { + if (string.IsNullOrEmpty (options.CompilerToUse)) + return CompileCSharpAssemblyWithDefaultCompiler (options); + + if (options.CompilerToUse == "csc") + return CompileCSharpAssemblyWithCsc (options); + + if (options.CompilerToUse == "mcs") + return CompileCSharpAssemblyWithMcs (options); + + throw new ArgumentException ($"Invalid compiler value `{options.CompilerToUse}`"); + } + + protected NPath CompileIlAssembly (CompilerOptions options) + { + return _ilCompiler.Compile (options); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs new file mode 100644 index 0000000000000..161e9af1c33ce --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; + +#nullable disable + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseLinkerOptions + { + public string TrimMode; + public string DefaultAssembliesAction; + public List<(string Action, string Assembly)> AssembliesAction = new(); + + public string Il8n; + public bool IgnoreDescriptors; + public bool IgnoreSubstitutions; + public bool IgnoreLinkAttributes; + public string KeepTypeForwarderOnlyAssemblies; + public string KeepDebugMembers; + public string LinkSymbols; + public bool SkipUnresolved; + public bool StripDescriptors; + public bool StripSubstitutions; + public bool StripLinkAttributes; + + public List> AdditionalArguments = new List> (); + + public List Descriptors = new List (); + + public List Substitutions = new List (); + + public List LinkAttributes = new List (); + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs new file mode 100644 index 0000000000000..cf3a762396379 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs @@ -0,0 +1,141 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseMetadataProvider : BaseMetadataProvider + { + public TestCaseMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition) + : base (testCase, fullTestCaseAssemblyDefinition) + { + } + + public virtual TestCaseLinkerOptions GetLinkerOptions (NPath inputPath) + { + var tclo = new TestCaseLinkerOptions { + Il8n = GetOptionAttributeValue (nameof (Il8nAttribute), "none"), + IgnoreDescriptors = GetOptionAttributeValue (nameof (IgnoreDescriptorsAttribute), true), + IgnoreSubstitutions = GetOptionAttributeValue (nameof (IgnoreSubstitutionsAttribute), true), + IgnoreLinkAttributes = GetOptionAttributeValue (nameof (IgnoreLinkAttributesAttribute), true), + KeepTypeForwarderOnlyAssemblies = GetOptionAttributeValue (nameof (KeepTypeForwarderOnlyAssembliesAttribute), string.Empty), + KeepDebugMembers = GetOptionAttributeValue (nameof (SetupLinkerKeepDebugMembersAttribute), string.Empty), + LinkSymbols = GetOptionAttributeValue (nameof (SetupLinkerLinkSymbolsAttribute), string.Empty), + TrimMode = GetOptionAttributeValue (nameof (SetupLinkerTrimModeAttribute), null), + DefaultAssembliesAction = GetOptionAttributeValue (nameof (SetupLinkerDefaultActionAttribute), null), + SkipUnresolved = GetOptionAttributeValue (nameof (SkipUnresolvedAttribute), false), + StripDescriptors = GetOptionAttributeValue (nameof (StripDescriptorsAttribute), true), + StripSubstitutions = GetOptionAttributeValue (nameof (StripSubstitutionsAttribute), true), + StripLinkAttributes = GetOptionAttributeValue (nameof (StripLinkAttributesAttribute), true), + }; + + foreach (var assemblyAction in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerActionAttribute))) { + var ca = assemblyAction.ConstructorArguments; + tclo.AssembliesAction.Add (((string) ca[0].Value, (string) ca[1].Value)); + } + + foreach (var descFile in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerDescriptorFile))) { + var ca = descFile.ConstructorArguments; + var file = (string) ca[0].Value; + tclo.Descriptors.Add (Path.Combine (inputPath, file)); + } + + foreach (var subsFile in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerSubstitutionFileAttribute))) { + var ca = subsFile.ConstructorArguments; + var file = (string) ca[0].Value; + tclo.Substitutions.Add (Path.Combine (inputPath, file)); + } + + foreach (var linkAttrFile in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkAttributesFile))) { + var ca = linkAttrFile.ConstructorArguments; + var file = (string) ca[0].Value; + tclo.LinkAttributes.Add (Path.Combine (inputPath, file)); + } + + foreach (var additionalArgumentAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerArgumentAttribute))) { + var ca = additionalArgumentAttr.ConstructorArguments; + var values = ((CustomAttributeArgument[]) ca[1].Value)!.Select (arg => arg.Value.ToString ()!).ToArray (); + // Since custom attribute arguments need to be constant expressions, we need to add + // the path to the temp directory (where the custom assembly is located) here. + switch ((string) ca[0].Value) { + case "--custom-step": + int pos = values[0].IndexOf (","); + if (pos != -1) { + string custom_assembly_path = values[0].Substring (pos + 1); + if (!Path.IsPathRooted (custom_assembly_path)) + values[0] = values[0].Substring (0, pos + 1) + Path.Combine (inputPath, custom_assembly_path); + } + break; + case "-a": + if (!Path.IsPathRooted (values[0])) + values[0] = Path.Combine (inputPath, values[0]); + + break; + } + + tclo.AdditionalArguments.Add (new KeyValuePair ((string) ca[0].Value, values)); + } + + return tclo; + } + + public virtual IEnumerable GetResponseFiles () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupLinkerResponseFileAttribute)) + .Select (GetSourceAndRelativeDestinationValue); + } + + public virtual IEnumerable GetDescriptorFiles () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupLinkerDescriptorFile)) + .Select (GetSourceAndRelativeDestinationValue); + } + + public virtual IEnumerable GetSubstitutionFiles () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupLinkerSubstitutionFileAttribute)) + .Select (GetSourceAndRelativeDestinationValue); + } + + public virtual IEnumerable GetLinkAttributesFiles () + { + return _testCaseTypeDefinition.CustomAttributes + .Where (attr => attr.AttributeType.Name == nameof (SetupLinkAttributesFile)) + .Select (GetSourceAndRelativeDestinationValue); + } + + public virtual IEnumerable GetExtraLinkerReferences () + { + var netcoreappDir = Path.GetDirectoryName (typeof (object).Assembly.Location)!; + foreach (var assembly in Directory.EnumerateFiles (netcoreappDir)) { + if (Path.GetExtension (assembly) != ".dll") + continue; + var assemblyName = Path.GetFileNameWithoutExtension (assembly); + if (assemblyName.Contains ("Native")) + continue; + if (assemblyName.StartsWith ("Microsoft") || + assemblyName.StartsWith ("System") || + assemblyName == "mscorlib" || assemblyName == "netstandard") + yield return assembly.ToNPath (); + } + } + + public virtual bool LinkPublicAndFamily () + { + return _testCaseTypeDefinition.CustomAttributes + .FirstOrDefault (attr => attr.AttributeType.Name == nameof (SetupLinkerLinkPublicAndFamilyAttribute)) != null; + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs new file mode 100644 index 0000000000000..c7041020c4481 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs @@ -0,0 +1,195 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestCaseSandbox + { + protected readonly TestCase _testCase; + protected readonly NPath _directory; + + static readonly string _linkerAssemblyPath = "";//typeof (Trimmer).Assembly.Location; + + static NPath GetArtifactsTestPath () + { + // Converts paths like /root-folder/runtime/artifacts/bin/Mono.Linker.Tests/x64/Debug/Mono.Linker.Tests.dll + // to /root-folder/runtime/artifacts/bin/ILLink.testcases/ + string artifacts = (string) AppContext.GetData ("Mono.Linker.Tests.ArtifactsDir")!; + string tests = Path.Combine (artifacts, "ILLink.testcases"); + return new NPath (tests); + } + + public TestCaseSandbox (TestCase testCase) + : this (testCase, GetArtifactsTestPath (), Path.GetFileNameWithoutExtension (_linkerAssemblyPath)) + { + } + + public TestCaseSandbox (TestCase testCase, NPath rootTemporaryDirectory) + : this (testCase, rootTemporaryDirectory, string.Empty) + { + } + + public TestCaseSandbox (TestCase testCase, string rootTemporaryDirectory, string namePrefix) + : this (testCase, rootTemporaryDirectory.ToNPath (), namePrefix) + { + } + + public TestCaseSandbox (TestCase testCase, NPath rootTemporaryDirectory, string namePrefix) + { + _testCase = testCase; + + var rootDirectory = rootTemporaryDirectory.Combine (string.IsNullOrEmpty (namePrefix) ? "linker_tests" : namePrefix); + + var locationRelativeToRoot = testCase.SourceFile.Parent.RelativeTo (testCase.RootCasesDirectory); + var suiteDirectory = rootDirectory.Combine (locationRelativeToRoot); + _directory = suiteDirectory.Combine (testCase.SourceFile.FileNameWithoutExtension); + + _directory.DeleteContents (); + + InputDirectory = _directory.Combine ("input").EnsureDirectoryExists (); + OutputDirectory = _directory.Combine ("output").EnsureDirectoryExists (); + ExpectationsDirectory = _directory.Combine ("expectations").EnsureDirectoryExists (); + ResourcesDirectory = _directory.Combine ("resources").EnsureDirectoryExists (); + } + + public NPath InputDirectory { get; } + + public NPath OutputDirectory { get; } + + public NPath ExpectationsDirectory { get; } + + public NPath ResourcesDirectory { get; } + + public IEnumerable SourceFiles { + get { return _directory.Files ("*.cs"); } + } + + public IEnumerable ResponseFiles { + get { return InputDirectory.Files ("*.rsp"); } + } + + public IEnumerable ResourceFiles => ResourcesDirectory.Files (); + + public virtual void Populate (TestCaseCompilationMetadataProvider metadataProvider) + { + _testCase.SourceFile.Copy (_directory); + + if (_testCase.HasLinkXmlFile) + _testCase.LinkXmlFile.Copy (InputDirectory); + + CopyToInputAndExpectations (GetExpectationsAssemblyPath ()); + + foreach (var dep in metadataProvider.AdditionalFilesToSandbox ()) { + var destination = _directory.Combine (dep.DestinationFileName); + dep.Source.FileMustExist ().Copy (destination); + + // In a few niche tests we need to copy pre-built assemblies directly into the input directory. + // When this is done, we also need to copy them into the expectations directory so that if they are used + // as references we can still compile the expectations version of the assemblies + if (destination.Parent == InputDirectory) + dep.Source.Copy (ExpectationsDirectory.Combine (destination.RelativeTo (InputDirectory))); + } + + // Copy non class library dependencies to the sandbox + foreach (var fileName in metadataProvider.GetReferenceValues ()) { + if (!fileName.StartsWith ("System.", StringComparison.Ordinal) && !fileName.StartsWith ("Mono.", StringComparison.Ordinal) && !fileName.StartsWith ("Microsoft.", StringComparison.Ordinal)) + CopyToInputAndExpectations (_testCase.SourceFile.Parent.Combine (fileName.ToNPath ())); + } + + foreach (var referenceDependency in metadataProvider.GetReferenceDependencies ()) + CopyToInputAndExpectations (_testCase.SourceFile.Parent.Combine (referenceDependency.ToNPath ())); + + foreach (var res in metadataProvider.GetResources ()) { + res.Source.FileMustExist ().Copy (ResourcesDirectory.Combine (res.DestinationFileName)); + } + + foreach (var compileRefInfo in metadataProvider.GetSetupCompileAssembliesBefore ()) { + var destination = BeforeReferenceSourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); + compileRefInfo.SourceFiles.Copy (destination); + + destination = BeforeReferenceResourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); + + if (compileRefInfo.Resources == null) + continue; + + foreach (var res in compileRefInfo.Resources) + res.Source.FileMustExist ().Copy (destination.Combine (res.DestinationFileName)); + } + + foreach (var compileRefInfo in metadataProvider.GetSetupCompileAssembliesAfter ()) { + var destination = AfterReferenceSourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); + compileRefInfo.SourceFiles.Copy (destination); + + destination = AfterReferenceResourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); + + if (compileRefInfo.Resources == null) + continue; + + foreach (var res in compileRefInfo.Resources) + res.Source.FileMustExist ().Copy (destination.Combine (res.DestinationFileName)); + } + } + + /// + /// Any files that are needed for linking should come from the expectations assembly so that these values + /// can be controlled using #ifs regardless of the framework the NUnit test project is compiled against + /// + /// + public virtual void PopulateFromExpectations (TestCaseMetadataProvider metadataProvider) + { + foreach (var res in metadataProvider.GetResponseFiles ()) { + res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName)); + } + + foreach (var res in metadataProvider.GetDescriptorFiles ()) { + res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName)); + } + + foreach (var res in metadataProvider.GetSubstitutionFiles ()) { + res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName)); + } + + foreach (var res in metadataProvider.GetLinkAttributesFiles ()) { + res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName)); + } + } + + private static NPath GetExpectationsAssemblyPath () + { + return new Uri (typeof (KeptAttribute).Assembly.Location).LocalPath.ToNPath (); + } + + protected void CopyToInputAndExpectations (NPath source) + { + source.Copy (InputDirectory); + source.Copy (ExpectationsDirectory); + } + + public NPath BeforeReferenceSourceDirectoryFor (string outputName) + { + return _directory.Combine ($"ref_source_before_{Path.GetFileNameWithoutExtension (outputName)}"); + } + + public NPath AfterReferenceSourceDirectoryFor (string outputName) + { + return _directory.Combine ($"ref_source_after_{Path.GetFileNameWithoutExtension (outputName)}"); + } + + public NPath BeforeReferenceResourceDirectoryFor (string outputName) + { + return _directory.Combine ($"ref_resource_before_{Path.GetFileNameWithoutExtension (outputName)}"); + } + + public NPath AfterReferenceResourceDirectoryFor (string outputName) + { + return _directory.Combine ($"ref_resource_after_{Path.GetFileNameWithoutExtension (outputName)}"); + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestLogWriter.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestLogWriter.cs new file mode 100644 index 0000000000000..c8d4a40a7eabd --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestLogWriter.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; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ILCompiler; +using ILCompiler.Logging; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestLogWriter : ILogWriter + { + private readonly StringWriter _infoStringWriter; + private readonly TextWriter _infoWriter; + + private readonly List _messageContainers; + + public TestLogWriter () + { + _infoStringWriter = new StringWriter (); + _infoWriter = TextWriter.Synchronized (_infoStringWriter); + _messageContainers = new List (); + } + + public TextWriter Writer => _infoWriter; + + public List GetLoggedMessages () + { + return _messageContainers; + } + + public void WriteError (MessageContainer error) + { + lock (_messageContainers) { + _messageContainers.Add (error); + } + } + + public void WriteMessage (MessageContainer message) + { + lock (_messageContainers) { + _messageContainers.Add (message); + } + } + + public void WriteWarning (MessageContainer warning) + { + lock (_messageContainers) { + _messageContainers.Add (warning); + } + } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs new file mode 100644 index 0000000000000..3540250b709f3 --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs @@ -0,0 +1,165 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using System.Threading.Tasks; +using Mono.Linker.Tests.TestCasesRunner; +using Mono.Cecil; +using Mono.Linker.Tests.Extensions; +using Mono.Linker.Tests.TestCases; +using Xunit.Sdk; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + public class TestRunner + { + private readonly ObjectFactory _factory; + + public TestRunner (ObjectFactory factory) + { + _factory = factory; + } + + public virtual ILCompilerTestCaseResult? Run (TestCase testCase) + { + try { + using (var fullTestCaseAssemblyDefinition = AssemblyDefinition.ReadAssembly (testCase.OriginalTestCaseAssemblyPath.ToString ())) { + var compilationMetadataProvider = _factory.CreateCompilationMetadataProvider (testCase, fullTestCaseAssemblyDefinition); + + if (compilationMetadataProvider.IsIgnored (out string? ignoreReason)) + throw new IgnoreTestException (ignoreReason); + + var sandbox = Sandbox (testCase, compilationMetadataProvider); + var compilationResult = Compile (sandbox, compilationMetadataProvider); + using (var expectationsAssemblyDefinition = AssemblyDefinition.ReadAssembly (compilationResult.ExpectationsAssemblyPath.ToString ())) { + var metadataProvider = _factory.CreateMetadataProvider (testCase, expectationsAssemblyDefinition); + + sandbox.PopulateFromExpectations (metadataProvider); + + PrepForLink (sandbox, compilationResult); + return Link (testCase, sandbox, compilationResult, metadataProvider); + } + } + } catch (IgnoreTestException) { + return null; + } + } + + public virtual ILCompilerTestCaseResult Relink (ILCompilerTestCaseResult result) + { + PrepForLink (result.Sandbox, result.CompilationResult); + return Link (result.TestCase, result.Sandbox, result.CompilationResult, result.MetadataProvider); + } + + private TestCaseSandbox Sandbox (TestCase testCase, TestCaseCompilationMetadataProvider metadataProvider) + { + var sandbox = _factory.CreateSandbox (testCase); + sandbox.Populate (metadataProvider); + return sandbox; + } + + private ManagedCompilationResult Compile (TestCaseSandbox sandbox, TestCaseCompilationMetadataProvider metadataProvider) + { + var inputCompiler = _factory.CreateCompiler (sandbox, metadataProvider); + var expectationsCompiler = _factory.CreateCompiler (sandbox, metadataProvider); + var sourceFiles = sandbox.SourceFiles.Select (s => s.ToString ()).ToArray (); + + var assemblyName = metadataProvider.GetAssemblyName (); + + var commonReferences = metadataProvider.GetCommonReferencedAssemblies (sandbox.InputDirectory).ToArray (); + var mainAssemblyReferences = metadataProvider.GetReferencedAssemblies (sandbox.InputDirectory).ToArray (); + var resources = sandbox.ResourceFiles.ToArray (); + var additionalArguments = metadataProvider.GetSetupCompilerArguments ().ToArray (); + + var expectationsCommonReferences = metadataProvider.GetCommonReferencedAssemblies (sandbox.ExpectationsDirectory).ToArray (); + var expectationsMainAssemblyReferences = metadataProvider.GetReferencedAssemblies (sandbox.ExpectationsDirectory).ToArray (); + + var inputTask = Task.Run (() => inputCompiler.CompileTestIn (sandbox.InputDirectory, assemblyName!, sourceFiles, commonReferences, mainAssemblyReferences, null, resources, additionalArguments)); + var expectationsTask = Task.Run (() => expectationsCompiler.CompileTestIn (sandbox.ExpectationsDirectory, assemblyName!, sourceFiles, expectationsCommonReferences, expectationsMainAssemblyReferences, new[] { "INCLUDE_EXPECTATIONS" }, resources, additionalArguments)); + + NPath? inputAssemblyPath = null; + NPath? expectationsAssemblyPath = null; + try { + inputAssemblyPath = GetResultOfTaskThatMakesXUnitAssertions (inputTask); + expectationsAssemblyPath = GetResultOfTaskThatMakesXUnitAssertions (expectationsTask); + } catch (Exception) { + // If completing the input assembly task threw, we need to wait for the expectations task to complete before continuing + // otherwise we could set the next test up for a race condition with the expectations compilation over access to the sandbox directory + if (inputAssemblyPath == null && expectationsAssemblyPath == null) { + try { + expectationsTask.Wait (); + } catch (Exception) { + // Don't care, we want to throw the first exception + } + } + + throw; + } + + return new ManagedCompilationResult (inputAssemblyPath, expectationsAssemblyPath); + } + + protected virtual void PrepForLink (TestCaseSandbox sandbox, ManagedCompilationResult compilationResult) + { + } + + private ILCompilerTestCaseResult Link (TestCase testCase, TestCaseSandbox sandbox, ManagedCompilationResult compilationResult, TestCaseMetadataProvider metadataProvider) + { + var trimmer = _factory.CreateTrimmer (); + + var builder = _factory.CreateTrimmerOptionsBuilder (metadataProvider); + + AddLinkOptions (sandbox, compilationResult, builder, metadataProvider); + + var logWriter = new TestLogWriter (); + trimmer.Trim (builder.Options, logWriter); + + return new ILCompilerTestCaseResult (testCase, compilationResult.InputAssemblyPath, compilationResult.ExpectationsAssemblyPath, sandbox, metadataProvider, compilationResult, logWriter); + } + + protected virtual void AddLinkOptions (TestCaseSandbox sandbox, ManagedCompilationResult compilationResult, ILCompilerOptionsBuilder builder, TestCaseMetadataProvider metadataProvider) + { + var caseDefinedOptions = metadataProvider.GetLinkerOptions (sandbox.InputDirectory); + + builder.AddOutputDirectory (sandbox.OutputDirectory.Combine (compilationResult.InputAssemblyPath.FileNameWithoutExtension + ".obj")); + + foreach (var rspFile in sandbox.ResponseFiles) + builder.AddResponseFile (rspFile); + + foreach (var inputReference in sandbox.InputDirectory.Files ()) { + var ext = inputReference.ExtensionWithDot; + if (ext == ".dll" || ext == ".exe") { + if (caseDefinedOptions.AssembliesAction.Contains (("link", inputReference.FileNameWithoutExtension))) { + builder.AddLinkAssembly (inputReference); + } else { + builder.AddReference (inputReference); + } + } + } + var coreAction = caseDefinedOptions.TrimMode ?? "skip"; + foreach (var extraReference in metadataProvider.GetExtraLinkerReferences ()) { + builder.AddReference (extraReference); + builder.AddAssemblyAction (coreAction, extraReference.FileNameWithoutExtension); + } + + builder.ProcessOptions (caseDefinedOptions); + + builder.ProcessTestInputAssembly (compilationResult.InputAssemblyPath); + } + + private T GetResultOfTaskThatMakesXUnitAssertions (Task task) + { + try { + return task.Result; + } catch (AggregateException e) { + if (e.InnerException != null) { + if (e.InnerException is XunitException) + throw e.InnerException; + } + + throw; + } + } + } +} diff --git a/src/coreclr/tools/aot/ilc.sln b/src/coreclr/tools/aot/ilc.sln index b1c7181908a26..2ea6f046a1b26 100644 --- a/src/coreclr/tools/aot/ilc.sln +++ b/src/coreclr/tools/aot/ilc.sln @@ -22,11 +22,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Compiler.Tests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.TypeSystem.Tests", "ILCompiler.TypeSystem.Tests\ILCompiler.TypeSystem.Tests.csproj", "{740CDFF4-B8EC-4A37-951B-C9FE9980EF2A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker.Tests", "Mono.Linker.Tests\Mono.Linker.Tests.csproj", "{4CF2ECD3-A1C3-4A28-AB08-A61C53114143}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker.Tests.Cases", "Mono.Linker.Tests.Cases\Mono.Linker.Tests.Cases.csproj", "{13F90593-7DF6-4B16-B6C1-283905C05A6A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mono.Linker.Tests.Cases.Expectations", "Mono.Linker.Tests.Cases.Expectations\Mono.Linker.Tests.Cases.Expectations.csproj", "{26C08C03-921E-4795-AA0B-F3049416E300}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 - ILLink.Shared\ILLink.Shared.projitems*{ffbd9619-de6f-4a98-8732-8a14ec3c1a18}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|Any CPU = Checked|Any CPU Checked|x64 = Checked|x64 @@ -180,6 +182,60 @@ Global {740CDFF4-B8EC-4A37-951B-C9FE9980EF2A}.Release|x64.Build.0 = Release|x64 {740CDFF4-B8EC-4A37-951B-C9FE9980EF2A}.Release|x86.ActiveCfg = Release|Any CPU {740CDFF4-B8EC-4A37-951B-C9FE9980EF2A}.Release|x86.Build.0 = Release|Any CPU + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|Any CPU.ActiveCfg = Checked|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|Any CPU.Build.0 = Checked|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|x64.ActiveCfg = Checked|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|x64.Build.0 = Checked|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|x86.ActiveCfg = Checked|x86 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Checked|x86.Build.0 = Checked|x86 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|Any CPU.Build.0 = Debug|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|x64.ActiveCfg = Debug|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|x64.Build.0 = Debug|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|x86.ActiveCfg = Debug|x86 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Debug|x86.Build.0 = Debug|x86 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|Any CPU.ActiveCfg = Release|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|Any CPU.Build.0 = Release|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|x64.ActiveCfg = Release|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|x64.Build.0 = Release|x64 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|x86.ActiveCfg = Release|x86 + {4CF2ECD3-A1C3-4A28-AB08-A61C53114143}.Release|x86.Build.0 = Release|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|Any CPU.ActiveCfg = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|Any CPU.Build.0 = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|x64.ActiveCfg = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|x64.Build.0 = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|x86.ActiveCfg = Debug|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Checked|x86.Build.0 = Debug|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|Any CPU.ActiveCfg = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|Any CPU.Build.0 = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|x64.ActiveCfg = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|x64.Build.0 = Debug|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|x86.ActiveCfg = Debug|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Debug|x86.Build.0 = Debug|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|Any CPU.ActiveCfg = Release|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|Any CPU.Build.0 = Release|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|x64.ActiveCfg = Release|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|x64.Build.0 = Release|x64 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|x86.ActiveCfg = Release|x86 + {13F90593-7DF6-4B16-B6C1-283905C05A6A}.Release|x86.Build.0 = Release|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|Any CPU.ActiveCfg = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|Any CPU.Build.0 = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|x64.ActiveCfg = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|x64.Build.0 = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|x86.ActiveCfg = Debug|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Checked|x86.Build.0 = Debug|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|Any CPU.ActiveCfg = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|Any CPU.Build.0 = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|x64.ActiveCfg = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|x64.Build.0 = Debug|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|x86.ActiveCfg = Debug|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Debug|x86.Build.0 = Debug|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|Any CPU.ActiveCfg = Release|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|Any CPU.Build.0 = Release|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|x64.ActiveCfg = Release|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|x64.Build.0 = Release|x64 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|x86.ActiveCfg = Release|x86 + {26C08C03-921E-4795-AA0B-F3049416E300}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -187,4 +243,8 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A484CF9D-B203-427F-9D15-A5BBC6013421} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ILLink.Shared\ILLink.Shared.projitems*{ff598e93-8e9e-4091-9f50-61a7572663ae}*SharedItemsImports = 13 + ILLink.Shared\ILLink.Shared.projitems*{ffbd9619-de6f-4a98-8732-8a14ec3c1a18}*SharedItemsImports = 5 + EndGlobalSection EndGlobal diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index d182b8fee80ee..bad094900a090 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -17,6 +17,7 @@ struct JitInterfaceCallbacks void (* getMethodSig)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent); bool (* getMethodInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info); CorInfoInline (* canInline)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd); + void (* beginInlining)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd); void (* reportInliningDecision)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char* reason); bool (* canTailCall)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE declaredCalleeHnd, CORINFO_METHOD_HANDLE exactCalleeHnd, bool fIsTailPrefix); void (* reportTailCallDecision)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, const char* reason); @@ -255,6 +256,15 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual void beginInlining( + CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->beginInlining(_thisHandle, &pException, inlinerHnd, inlineeHnd); + if (pException != nullptr) throw pException; +} + virtual void reportInliningDecision( CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, diff --git a/src/coreclr/tools/dotnet-pgo/MibcEmitter.cs b/src/coreclr/tools/dotnet-pgo/MibcEmitter.cs index a498bfd9e21d5..e99fc610d86ca 100644 --- a/src/coreclr/tools/dotnet-pgo/MibcEmitter.cs +++ b/src/coreclr/tools/dotnet-pgo/MibcEmitter.cs @@ -215,6 +215,8 @@ private static void AddAssembliesAssociatedWithMethod(MethodDesc method, HashSet public static int GenerateMibcFile(TypeSystemContext tsc, FileInfo outputFileName, IEnumerable methodsToAttemptToPlaceIntoProfileData, bool validate, bool uncompressed) { TypeSystemMetadataEmitter emitter = new TypeSystemMetadataEmitter(new AssemblyName(outputFileName.Name), tsc); + emitter.InjectSystemPrivateCanon(); + emitter.AllowUseOfAddGlobalMethod(); SortedDictionary groups = new SortedDictionary(); StringBuilder mibcGroupNameBuilder = new StringBuilder(); diff --git a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs index bb32521c0b750..31a5caee14c23 100644 --- a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs +++ b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs @@ -153,8 +153,8 @@ public TypeRefTypeSystemContext(IEnumerable refReaders) } else { - var fieldType = ecmaSigParse.ParseFieldSignature(); - ownerType.GetOrAddField(name, fieldType); + var fieldType = ecmaSigParse.ParseFieldSignature(out var embeddedSigData); + ownerType.GetOrAddField(name, fieldType, embeddedSigData); } } diff --git a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemField.cs b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemField.cs index 5f261b4932c3f..a380db86080bc 100644 --- a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemField.cs +++ b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemField.cs @@ -15,12 +15,14 @@ class TypeRefTypeSystemField : FieldDesc TypeRefTypeSystemType _type; string _name; TypeDesc _fieldType; + EmbeddedSignatureData[] _embeddedSignatureData; - public TypeRefTypeSystemField(TypeRefTypeSystemType type, string name, TypeDesc fieldType) + public TypeRefTypeSystemField(TypeRefTypeSystemType type, string name, TypeDesc fieldType, EmbeddedSignatureData[] embeddedSigData) { _type = type; _name = name; _fieldType = fieldType; + _embeddedSignatureData = embeddedSigData; } public override string Name => _name; @@ -28,6 +30,8 @@ public TypeRefTypeSystemField(TypeRefTypeSystemType type, string name, TypeDesc public override TypeDesc FieldType => _fieldType; + public override EmbeddedSignatureData[] GetEmbeddedSignatureData() => _embeddedSignatureData; + public override bool IsStatic => throw new NotImplementedException(); public override bool IsInitOnly => throw new NotImplementedException(); diff --git a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemType.cs b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemType.cs index 6b5689805e93c..af3bb5ae72c24 100644 --- a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemType.cs +++ b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemType.cs @@ -119,12 +119,12 @@ public MethodDesc GetOrAddMethod(string name, MethodSignature signature) return method; } - public FieldDesc GetOrAddField(string name, TypeDesc fieldType) + public FieldDesc GetOrAddField(string name, TypeDesc fieldType, EmbeddedSignatureData[] embeddedSigData) { FieldDesc fld = GetField(name); if (fld == null) { - TypeRefTypeSystemField newField = new TypeRefTypeSystemField(this, name, fieldType); + TypeRefTypeSystemField newField = new TypeRefTypeSystemField(this, name, fieldType, embeddedSigData); fld = newField; _fields.Add(newField); } diff --git a/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp b/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp index 1cfbc598dbee1..2ff9b3cbe3690 100644 --- a/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp +++ b/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp @@ -93,8 +93,9 @@ void DumpMap(int index, MethodContext* mc) bool hasClassProfile = false; bool hasMethodProfile = false; bool hasLikelyClass = false; + bool hasLikelyMethod = false; ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, pgoSource)) + if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, hasLikelyMethod, pgoSource)) { rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO); @@ -118,6 +119,11 @@ void DumpMap(int index, MethodContext* mc) rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); } + if (hasLikelyMethod) + { + rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); + } + if (pgoSource == ICorJitInfo::PgoSource::Static) { rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); diff --git a/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp b/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp index a3e31a1f73062..33190d3fbd996 100644 --- a/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp +++ b/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp @@ -31,8 +31,9 @@ int verbJitFlags::DoWork(const char* nameOfInput) bool hasClassProfile = false; bool hasMethodProfile = false; bool hasLikelyClass = false; + bool hasLikelyMethod = false; ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, pgoSource)) + if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, hasLikelyMethod, pgoSource)) { rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO); @@ -56,6 +57,11 @@ int verbJitFlags::DoWork(const char* nameOfInput) rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); } + if (hasLikelyMethod) + { + rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); + } + if (pgoSource == ICorJitInfo::PgoSource::Static) { rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 97be9fbfc9fca..df50466b476d3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5607,9 +5607,10 @@ void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnosti } break; case ICorJitInfo::PgoInstrumentationKind::GetLikelyClass: + case ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod: { - // (N)umber, (L)ikelihood, (C)lass - printf("N %u L %u C %016llX", (unsigned)(pBuf[i].Other >> 8), (unsigned)(pBuf[i].Other && 0xFF), CastHandle(*(uintptr_t*)(pInstrumentationData + pBuf[i].Offset))); + // (N)umber, (L)ikelihood, (H)andle + printf("N %u L %u H %016llX", (unsigned)(pBuf[i].Other >> 8), (unsigned)(pBuf[i].Other && 0xFF), CastHandle(*(uintptr_t*)(pInstrumentationData + pBuf[i].Offset))); } break; default: @@ -7072,12 +7073,13 @@ int MethodContext::dumpMD5HashToBuffer(BYTE* pBuffer, int bufLen, char* hash, in return m_hash.HashBuffer(pBuffer, bufLen, hash, hashLen); } -bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, ICorJitInfo::PgoSource& pgoSource) +bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, bool& hasLikelyMethod, ICorJitInfo::PgoSource& pgoSource) { hasEdgeProfile = false; hasClassProfile = false; hasMethodProfile = false; hasLikelyClass = false; + hasLikelyMethod = false; // Obtain the Method Info structure for this method CORINFO_METHOD_INFO info; @@ -7102,8 +7104,9 @@ bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool hasClassProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes); hasMethodProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods); hasLikelyClass |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyClass); + hasLikelyMethod |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod); - if (hasEdgeProfile && hasClassProfile && hasLikelyClass) + if (hasEdgeProfile && hasClassProfile && hasLikelyClass && hasLikelyMethod) { break; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 816682b1effe9..5009d6b6a69c4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -54,6 +54,7 @@ enum EXTRA_JIT_FLAGS HAS_STATIC_PROFILE = 59, HAS_DYNAMIC_PROFILE = 58, HAS_METHOD_PROFILE = 57, + HAS_LIKELY_METHOD = 56, }; // Asserts to catch changes in corjit flags definitions. @@ -64,6 +65,8 @@ static_assert((int)EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE == (int)CORJIT_FLAGS::CorJ static_assert((int)EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED33, "Jit Flags Mismatch"); static_assert((int)EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED32, "Jit Flags Mismatch"); static_assert((int)EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED31, "Jit Flags Mismatch"); +static_assert((int)EXTRA_JIT_FLAGS::HAS_METHOD_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED30, "Jit Flags Mismatch"); +static_assert((int)EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED29, "Jit Flags Mismatch"); class MethodContext { @@ -106,7 +109,7 @@ class MethodContext int dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); int dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); - bool hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, ICorJitInfo::PgoSource& pgoSource); + bool hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, bool& hasLikelyMethod, ICorJitInfo::PgoSource& pgoSource); void recGlobalContext(const MethodContext& other); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp index 1d1d4d53b1a84..b51a54ba18385 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp @@ -285,6 +285,7 @@ std::string SpmiDumpHelper::DumpJitFlags(unsigned long long flags) AddFlagNumeric(HAS_CLASS_PROFILE, EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE); AddFlagNumeric(HAS_METHOD_PROFILE, EXTRA_JIT_FLAGS::HAS_METHOD_PROFILE); AddFlagNumeric(HAS_LIKELY_CLASS, EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); + AddFlagNumeric(HAS_LIKELY_METHOD, EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); AddFlagNumeric(HAS_STATIC_PROFILE, EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); AddFlagNumeric(HAS_DYNAMIC_PROFILE, EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 4ce8db665615b..b939f4cb844fb 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -115,6 +115,13 @@ CorInfoInline interceptor_ICJI::canInline(CORINFO_METHOD_HANDLE callerHnd, /* return temp; } +void interceptor_ICJI::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + mc->cr->AddCall("beginInlining"); + original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); +} + // Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all // inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the // JIT. diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 79e3536ba524c..af768ca0933b1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -59,6 +59,14 @@ CorInfoInline interceptor_ICJI::canInline( return original_ICorJitInfo->canInline(callerHnd, calleeHnd); } +void interceptor_ICJI::beginInlining( + CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + mcs->AddCall("beginInlining"); + original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); +} + void interceptor_ICJI::reportInliningDecision( CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 7d4feacc10d6e..957cadd8c57c3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -53,6 +53,13 @@ CorInfoInline interceptor_ICJI::canInline( return original_ICorJitInfo->canInline(callerHnd, calleeHnd); } +void interceptor_ICJI::beginInlining( + CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); +} + void interceptor_ICJI::reportInliningDecision( CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 7f2203edd7ac1..bb6592bb8b39b 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -100,6 +100,11 @@ CorInfoInline MyICJI::canInline(CORINFO_METHOD_HANDLE callerHnd, /* IN */ return result; } +void MyICJI::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd) +{ + // do nothing +} // Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all // inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the // JIT. diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp index 5ed5f155c2d23..c43ed6fad684d 100644 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp +++ b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp @@ -371,7 +371,8 @@ int __cdecl main(int argc, char* argv[]) st3.Start(); res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput, &baseMetrics); st3.Stop(); - LogDebug("Method %d compiled in %fms, result %d", reader->GetMethodContextIndex(), st3.GetMilliseconds(), res); + LogDebug("Method %d compiled%s in %fms, result %d", + reader->GetMethodContextIndex(), (o.nameOfJit2 == nullptr) ? "" : " by JIT1", st3.GetMilliseconds(), res); totalBaseMetrics.AggregateFrom(baseMetrics); @@ -406,8 +407,8 @@ int __cdecl main(int argc, char* argv[]) if (res2 == JitInstance::RESULT_ERROR) { errorCount2++; - LogError("Method %d of size %d failed to load and compile correctly by JIT2.", - reader->GetMethodContextIndex(), mc->methodSize); + LogError("Method %d of size %d failed to load and compile correctly by JIT2 (%s).", + reader->GetMethodContextIndex(), mc->methodSize, o.nameOfJit2); if (errorCount2 == o.failureLimit) { LogError("More than %d methods compilation failed by JIT2. Skip compiling remaining methods.", o.failureLimit); @@ -565,11 +566,13 @@ int __cdecl main(int argc, char* argv[]) if (res == JitInstance::RESULT_ERROR) { errorCount++; - LogError("main method %d of size %d failed to load and compile correctly.", - reader->GetMethodContextIndex(), mc->methodSize); + LogError("Method %d of size %d failed to load and compile correctly%s (%s).", + reader->GetMethodContextIndex(), mc->methodSize, + (o.nameOfJit2 == nullptr) ? "" : " by JIT1", o.nameOfJit); if (errorCount == o.failureLimit) { - LogError("More than %d methods failed. Skip compiling remaining methods.", o.failureLimit); + LogError("More than %d methods failed%s. Skip compiling remaining methods.", + o.failureLimit, (o.nameOfJit2 == nullptr) ? "" : " by JIT1"); break; } if ((o.reproName != nullptr) && (o.indexCount == -1)) diff --git a/src/coreclr/unwinder/ppc64le/unwinder_ppc64le.cpp b/src/coreclr/unwinder/ppc64le/unwinder_ppc64le.cpp new file mode 100644 index 0000000000000..66cb24b46e6e7 --- /dev/null +++ b/src/coreclr/unwinder/ppc64le/unwinder_ppc64le.cpp @@ -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. + +// + +#include "stdafx.h" +#include "utilcode.h" +#include "crosscomp.h" + +#error Unsupported platform + diff --git a/src/coreclr/utilcode/CMakeLists.txt b/src/coreclr/utilcode/CMakeLists.txt index c55965b239600..76d5b0e61dc0f 100644 --- a/src/coreclr/utilcode/CMakeLists.txt +++ b/src/coreclr/utilcode/CMakeLists.txt @@ -27,7 +27,6 @@ set(UTILCODE_COMMON_SOURCES comex.cpp guidfromname.cpp memorypool.cpp - iallocator.cpp loaderheap.cpp outstring.cpp ilformatter.cpp diff --git a/src/coreclr/utilcode/clrconfig.cpp b/src/coreclr/utilcode/clrconfig.cpp index caad3b594a6ea..5df6748739ccb 100644 --- a/src/coreclr/utilcode/clrconfig.cpp +++ b/src/coreclr/utilcode/clrconfig.cpp @@ -200,15 +200,11 @@ namespace #if defined(DEBUG) && !defined(SELF_NO_HOST) // Validate the cache and no-cache logic result in the same answer SString nameToConvert(name); - SString nameAsUTF8; - nameToConvert.ConvertToUTF8(nameAsUTF8); - SString valueAsUTF8; - temp.ConvertToUTF8(valueAsUTF8); - CLRConfigNoCache nonCache = CLRConfigNoCache::Get(nameAsUTF8.GetUTF8NoConvert(), noPrefix); + CLRConfigNoCache nonCache = CLRConfigNoCache::Get(nameToConvert.GetUTF8(), noPrefix); LPCSTR valueNoCache = nonCache.AsString(); - _ASSERTE(SString::_stricmp(valueNoCache, valueAsUTF8.GetUTF8NoConvert()) == 0); + _ASSERTE(SString::_stricmp(valueNoCache, temp.GetUTF8()) == 0); #endif // defined(DEBUG) && !defined(SELF_NO_HOST) } } @@ -634,8 +630,8 @@ void CLRConfig::Initialize() if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableConfigCache) != 0) return; - const WCHAR prefixC = towlower(COMPLUS_PREFIX[0]); - const WCHAR prefixD = towlower(DOTNET_PREFIX[0]); + const WCHAR prefixC = (WCHAR)towlower(COMPLUS_PREFIX[0]); + const WCHAR prefixD = (WCHAR)towlower(DOTNET_PREFIX[0]); // Create a cache of environment variables WCHAR* wszStrings = GetEnvironmentStringsW(); @@ -645,7 +641,7 @@ void CLRConfig::Initialize() // null terminated strings for(WCHAR *wszCurr = wszStrings; *wszCurr; wszCurr++) { - WCHAR wch = towlower(*wszCurr); + WCHAR wch = (WCHAR)towlower(*wszCurr); // Lets only cache env variables with targeted prefixes bool matchC = wch == prefixC; diff --git a/src/coreclr/utilcode/debug.cpp b/src/coreclr/utilcode/debug.cpp index 3f4c74d420f9d..e78de404115e5 100644 --- a/src/coreclr/utilcode/debug.cpp +++ b/src/coreclr/utilcode/debug.cpp @@ -364,7 +364,7 @@ bool _DbgBreakCheck( " Image: %s\n\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), - szExpr, szFile, iLine, modulePath.GetUTF8NoConvert()); + szExpr, szFile, iLine, modulePath.GetUTF8()); formattedMessages = TRUE; } @@ -680,11 +680,11 @@ void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, cons " File: %s, Line: %d Image:\n%s\n", GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), - szExpr, szFile, iLine, modulePath.GetUTF8NoConvert()); - OutputDebugStringUtf8(buffer.GetUTF8NoConvert()); + szExpr, szFile, iLine, modulePath.GetUTF8()); + OutputDebugStringUtf8(buffer.GetUTF8()); // Write out the error to the console - printf(buffer.GetUTF8NoConvert()); + printf(buffer.GetUTF8()); // Log to the stress log. Note that we can't include the szExpr b/c that // may not be a string literal (particularly for formatt-able asserts). diff --git a/src/coreclr/utilcode/executableallocator.cpp b/src/coreclr/utilcode/executableallocator.cpp index 8a1614e080f6a..9536b673f53a5 100644 --- a/src/coreclr/utilcode/executableallocator.cpp +++ b/src/coreclr/utilcode/executableallocator.cpp @@ -249,7 +249,8 @@ bool ExecutableAllocator::Initialize() { if (!VMToOSInterface::CreateDoubleMemoryMapper(&m_doubleMemoryMapperHandle, &m_maxExecutableCodeSize)) { - return false; + g_isWXorXEnabled = false; + return true; } m_CriticalSection = ClrCreateCriticalSection(CrstExecutableAllocatorLock,CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD)); diff --git a/src/coreclr/utilcode/iallocator.cpp b/src/coreclr/utilcode/iallocator.cpp deleted file mode 100644 index 9e1ea5ed90662..0000000000000 --- a/src/coreclr/utilcode/iallocator.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "stdafx.h" // Precompiled header key. -#include "iallocator.h" -#include "defaultallocator.h" - -// static -DefaultAllocator DefaultAllocator::s_singleton; diff --git a/src/coreclr/utilcode/prettyprintsig.cpp b/src/coreclr/utilcode/prettyprintsig.cpp index ac6d7db6847dc..f6b187099f0aa 100644 --- a/src/coreclr/utilcode/prettyprintsig.cpp +++ b/src/coreclr/utilcode/prettyprintsig.cpp @@ -788,8 +788,12 @@ static HRESULT PrettyPrintTypeA( break; case ELEMENT_TYPE_FNPTR: - IfFailGo(appendStrA(out, "fnptr ")); - IfFailGo(PrettyPrintSigWorkerInternal(typePtr, (typeEnd - typePtr), "", out,pIMDI)); + { + IfFailGo(appendStrA(out, "fnptr ")); + CQuickBytes qbOut; + IfFailGo(PrettyPrintSigWorkerInternal(typePtr, (typeEnd - typePtr), "", &qbOut,pIMDI)); + IfFailGo(appendStrA(out, (char *)qbOut.Ptr())); + } break; case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: diff --git a/src/coreclr/utilcode/sstring.cpp b/src/coreclr/utilcode/sstring.cpp index ec3c340ff23d3..75e90977775af 100644 --- a/src/coreclr/utilcode/sstring.cpp +++ b/src/coreclr/utilcode/sstring.cpp @@ -469,6 +469,29 @@ void SString::SetANSI(const ANSI *string, COUNT_T count) SS_RETURN; } +//----------------------------------------------------------------------------- +// Set this string to a copy of the given UTF16 string transcoded to UTF8 +//----------------------------------------------------------------------------- +void SString::SetAndConvertToUTF8(const WCHAR *string) +{ + SS_CONTRACT_VOID + { + // !!! Check for illegal UTF8 encoding? + INSTANCE_CHECK; + PRECONDITION(CheckPointer(string, NULL_OK)); + THROWS; + GC_NOTRIGGER; + SUPPORTS_DAC_HOST_ONLY; + } + SS_CONTRACT_END; + + SString utf16Str(Literal, string); + + utf16Str.ConvertToUTF8(*this); + + SS_RETURN; +} + //----------------------------------------------------------------------------- // Set this string to the given unicode character //----------------------------------------------------------------------------- @@ -777,6 +800,39 @@ void SString::ConvertToUnicode(const CIterator &i) const RETURN; } +//----------------------------------------------------------------------------- +// Convert the internal representation for this String to UTF8. +//----------------------------------------------------------------------------- +void SString::ConvertToUTF8() const +{ + CONTRACT_VOID + { + POSTCONDITION(IsRepresentation(REPRESENTATION_UTF8)); + if (IsRepresentation(REPRESENTATION_UTF8)) NOTHROW; else THROWS; + GC_NOTRIGGER; + SUPPORTS_DAC_HOST_ONLY; + } + CONTRACT_END; + + if (!IsRepresentation(REPRESENTATION_UTF8)) + { + if (IsRepresentation(REPRESENTATION_ASCII)) + { + // ASCII is a subset of UTF8, so we can just set the representation. + (const_cast(this))->SetRepresentation(REPRESENTATION_UTF8); + } + else + { + StackSString s; + ConvertToUTF8(s); + PREFIX_ASSUME(!s.IsImmutable()); + (const_cast(this))->Set(s); + } + } + + RETURN; +} + //----------------------------------------------------------------------------- // Set s to be a copy of this string's contents, but in the unicode format. //----------------------------------------------------------------------------- @@ -1787,66 +1843,6 @@ const CHAR *SString::GetANSI(AbstractScratchBuffer &scratch) const SS_RETURN ((SString&)scratch).GetRawANSI(); } -//----------------------------------------------------------------------------- -// Get a const pointer to the internal buffer as a UTF8 string. -//----------------------------------------------------------------------------- -const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch) const -{ - CONTRACT(const UTF8 *) - { - INSTANCE_CHECK_NULL; - THROWS; - GC_NOTRIGGER; - } - CONTRACT_END; - - if (IsRepresentation(REPRESENTATION_UTF8)) - RETURN GetRawUTF8(); - - ConvertToUTF8((SString&)scratch); - RETURN ((SString&)scratch).GetRawUTF8(); -} - -const UTF8 *SString::GetUTF8(AbstractScratchBuffer &scratch, COUNT_T *pcbUtf8) const -{ - CONTRACT(const UTF8 *) - { - INSTANCE_CHECK_NULL; - THROWS; - GC_NOTRIGGER; - } - CONTRACT_END; - - if (IsRepresentation(REPRESENTATION_UTF8)) - { - *pcbUtf8 = GetRawCount() + 1; - RETURN GetRawUTF8(); - } - - *pcbUtf8 = ConvertToUTF8((SString&)scratch); - RETURN ((SString&)scratch).GetRawUTF8(); -} - -//----------------------------------------------------------------------------- -// Get a const pointer to the internal buffer which must already be a UTF8 string. -// This avoids the need to create a scratch buffer we know will never be used. -//----------------------------------------------------------------------------- -const UTF8 *SString::GetUTF8NoConvert() const -{ - CONTRACT(const UTF8 *) - { - INSTANCE_CHECK_NULL; - THROWS; - GC_NOTRIGGER; - } - CONTRACT_END; - - if (IsRepresentation(REPRESENTATION_UTF8)) - RETURN GetRawUTF8(); - - ThrowHR(E_INVALIDARG); -} - //----------------------------------------------------------------------------- // Safe version of sprintf. // Prints formatted ansi text w/ var args to this buffer. diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 58423a704e970..b4fec28360d24 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -23,6 +23,13 @@ #ifndef DACCESS_COMPILE UINT32 g_nClrInstanceId = 0; + +#if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) +// Flag to check if atomics feature is available on +// the machine +bool g_arm64_atomics_present = false; +#endif + #endif //!DACCESS_COMPILE //***************************************************************************** @@ -2593,161 +2600,6 @@ void PutArm64Rel12(UINT32 * pCode, INT32 imm12) _ASSERTE(GetArm64Rel12(pCode) == imm12); } -//--------------------------------------------------------------------- -// Splits a command line into argc/argv lists, using the VC7 parsing rules. -// -// This functions interface mimics the CommandLineToArgvW api. -// -// If function fails, returns NULL. -// -// If function suceeds, call delete [] on return pointer when done. -// -//--------------------------------------------------------------------- -// NOTE: Implementation-wise, once every few years it would be a good idea to -// compare this code with the C runtime library's parse_cmdline method, -// which is in vctools\crt\crtw32\startup\stdargv.c. (Note we don't -// support wild cards, and we use Unicode characters exclusively.) -// We are up to date as of ~6/2005. -//--------------------------------------------------------------------- -LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs) -{ - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_FAULT; - - - *pNumArgs = 0; - - int nch = (int)wcslen(lpCmdLine); - - // Calculate the worstcase storage requirement. (One pointer for - // each argument, plus storage for the arguments themselves.) - int cbAlloc = (nch+1)*sizeof(LPWSTR) + sizeof(WCHAR)*(nch + 1); - LPWSTR pAlloc = new (nothrow) WCHAR[cbAlloc / sizeof(WCHAR)]; - if (!pAlloc) - return NULL; - - LPWSTR *argv = (LPWSTR*) pAlloc; // We store the argv pointers in the first halt - LPWSTR pdst = (LPWSTR)( ((BYTE*)pAlloc) + sizeof(LPWSTR)*(nch+1) ); // A running pointer to second half to store arguments - LPCWSTR psrc = lpCmdLine; - WCHAR c; - BOOL inquote; - BOOL copychar; - int numslash; - - // First, parse the program name (argv[0]). Argv[0] is parsed under - // special rules. Anything up to the first whitespace outside a quoted - // subtring is accepted. Backslashes are treated as normal characters. - argv[ (*pNumArgs)++ ] = pdst; - inquote = FALSE; - do { - if (*psrc == W('"') ) - { - inquote = !inquote; - c = *psrc++; - continue; - } - *pdst++ = *psrc; - - c = *psrc++; - - } while ( (c != W('\0') && (inquote || (c != W(' ') && c != W('\t')))) ); - - if ( c == W('\0') ) { - psrc--; - } else { - *(pdst-1) = W('\0'); - } - - inquote = FALSE; - - - - /* loop on each argument */ - for(;;) - { - if ( *psrc ) - { - while (*psrc == W(' ') || *psrc == W('\t')) - { - ++psrc; - } - } - - if (*psrc == W('\0')) - break; /* end of args */ - - /* scan an argument */ - argv[ (*pNumArgs)++ ] = pdst; - - /* loop through scanning one argument */ - for (;;) - { - copychar = 1; - /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote - 2N+1 backslashes + " ==> N backslashes + literal " - N backslashes ==> N backslashes */ - numslash = 0; - while (*psrc == W('\\')) - { - /* count number of backslashes for use below */ - ++psrc; - ++numslash; - } - if (*psrc == W('"')) - { - /* if 2N backslashes before, start/end quote, otherwise - copy literally */ - if (numslash % 2 == 0) - { - if (inquote && psrc[1] == W('"')) - { - psrc++; /* Double quote inside quoted string */ - } - else - { - /* skip first quote char and copy second */ - copychar = 0; /* don't copy quote */ - inquote = !inquote; - } - } - numslash /= 2; /* divide numslash by two */ - } - - /* copy slashes */ - while (numslash--) - { - *pdst++ = W('\\'); - } - - /* if at end of arg, break loop */ - if (*psrc == W('\0') || (!inquote && (*psrc == W(' ') || *psrc == W('\t')))) - break; - - /* copy character into argument */ - if (copychar) - { - *pdst++ = *psrc; - } - ++psrc; - } - - /* null-terminate the argument */ - - *pdst++ = W('\0'); /* terminate string */ - } - - /* We put one last argument in -- a null ptr */ - argv[ (*pNumArgs) ] = NULL; - - // If we hit this assert, we overwrote our destination buffer. - // Since we're supposed to allocate for the worst - // case, either the parsing rules have changed or our worse case - // formula is wrong. - _ASSERTE((BYTE*)pdst <= (BYTE*)pAlloc + cbAlloc); - return argv; -} - //====================================================================== // This function returns true, if it can determine that the instruction pointer // refers to a code address that belongs in the range of the given image. diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 8c0b03342d016..6983f21238b23 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -364,7 +364,6 @@ set(VM_SOURCES_WKS runtimehandles.cpp safehandle.cpp simplerwlock.cpp - sourceline.cpp stackingallocator.cpp stringliteralmap.cpp stubcache.cpp @@ -465,7 +464,6 @@ set(VM_HEADERS_WKS reflectioninvocation.h runtimehandles.h simplerwlock.hpp - sourceline.h stackingallocator.h stringliteralmap.h stubcache.h diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index a55dec687c962..761d650be7e51 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -446,7 +446,13 @@ - + + + + + @@ -1579,6 +1585,24 @@ + +