diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 9087dea090bfca..ba0f3d9084908d 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.21602.2",
+ "version": "1.0.0-prerelease.21609.1",
"commands": [
"xharness"
]
diff --git a/.gitattributes b/.gitattributes
index b4e3bcd0745655..a25b1f94d6e5a4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -75,3 +75,4 @@ src/tests/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-
src/tests/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-input25000.txt text eol=lf
src/tests/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input.txt text eol=lf
src/tests/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input-big.txt text eol=lf
+src/mono/wasm/runtime/dotnet.d.ts text eol=lf
diff --git a/.github/fabricbot.json b/.github/fabricbot.json
new file mode 100644
index 00000000000000..836d070c0f65c4
--- /dev/null
+++ b/.github/fabricbot.json
@@ -0,0 +1,6966 @@
+[
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "Area-owners",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "area-System.Security"
+ ],
+ "mentionees": [
+ "dotnet/area-system-security",
+ "vcsjones",
+ "krwq"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.Tracing"
+ ],
+ "mentionees": [
+ "tarekgh",
+ "tommcdon",
+ "pjanotti",
+ "safern"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Linq.Parallel"
+ ],
+ "mentionees": [
+ "dotnet/area-system-linq-parallel",
+ "tarekgh"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Text.Encoding"
+ ],
+ "mentionees": [
+ "dotnet/area-system-text-encoding",
+ "tarekgh"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Text.Encodings.Web"
+ ],
+ "mentionees": [
+ "dotnet/area-system-text-encodings-web",
+ "tarekgh"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Threading.Channels"
+ ],
+ "mentionees": [
+ "dotnet/area-system-threading-channels"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Threading.Tasks"
+ ],
+ "mentionees": [
+ "dotnet/area-system-threading-tasks"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Text.RegularExpressions"
+ ],
+ "mentionees": [
+ "dotnet/area-system-text-regularexpressions"
+ ]
+ },
+ {
+ "labels": [
+ "area-GC-mono"
+ ],
+ "mentionees": [
+ "brzvlad"
+ ]
+ },
+ {
+ "labels": [
+ "area-Codegen-Interpreter-mono"
+ ],
+ "mentionees": [
+ "brzvlad"
+ ]
+ },
+ {
+ "labels": [
+ "area-Infrastructure-mono"
+ ],
+ "mentionees": [
+ "directhex"
+ ]
+ },
+ {
+ "labels": [
+ "area-AssemblyLoader-mono"
+ ],
+ "mentionees": []
+ },
+ {
+ "labels": [
+ "area-Debugger-mono"
+ ],
+ "mentionees": [
+ "thaystg"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Collections"
+ ],
+ "mentionees": [
+ "dotnet/area-system-collections"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Linq"
+ ],
+ "mentionees": [
+ "dotnet/area-system-linq"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Numerics.Tensors"
+ ],
+ "mentionees": [
+ "dotnet/area-system-numerics-tensors"
+ ]
+ },
+ {
+ "labels": [
+ "area-Host"
+ ],
+ "mentionees": [
+ "vitek-karas",
+ "agocke",
+ "vsadov"
+ ]
+ },
+ {
+ "labels": [
+ "area-HostModel"
+ ],
+ "mentionees": [
+ "vitek-karas",
+ "agocke"
+ ]
+ },
+ {
+ "labels": [
+ "area-Single-File"
+ ],
+ "mentionees": [
+ "agocke",
+ "vitek-karas",
+ "vsadov"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Buffers"
+ ],
+ "mentionees": [
+ "dotnet/area-system-buffers",
+ "GrabYourPitchforks"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Numerics"
+ ],
+ "mentionees": [
+ "dotnet/area-system-numerics"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Runtime.Intrinsics"
+ ],
+ "mentionees": [
+ "dotnet/area-system-runtime-intrinsics"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.CodeDom"
+ ],
+ "mentionees": [
+ "dotnet/area-system-codedom"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Xml"
+ ],
+ "mentionees": [
+ "dotnet/area-system-xml"
+ ]
+ },
+ {
+ "labels": [
+ "area-AssemblyLoader-coreclr"
+ ],
+ "mentionees": [
+ "vitek-karas",
+ "agocke",
+ "vsadov"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Dynamic.Runtime"
+ ],
+ "mentionees": [
+ "cston"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Linq.Expressions"
+ ],
+ "mentionees": [
+ "cston"
+ ]
+ },
+ {
+ "labels": [
+ "area-Microsoft.CSharp"
+ ],
+ "mentionees": [
+ "cston"
+ ]
+ },
+ {
+ "labels": [
+ "area-Microsoft.VisualBasic"
+ ],
+ "mentionees": [
+ "cston"
+ ]
+ },
+ {
+ "labels": [
+ "area-Infrastructure-libraries"
+ ],
+ "mentionees": [
+ "dotnet/area-infrastructure-libraries"
+ ]
+ },
+ {
+ "labels": [
+ "area-Infrastructure"
+ ],
+ "mentionees": [
+ "dotnet/runtime-infrastructure"
+ ]
+ },
+ {
+ "labels": [
+ "area-GC-coreclr"
+ ],
+ "mentionees": [
+ "dotnet/gc"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Net"
+ ],
+ "mentionees": [
+ "dotnet/ncl"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Net.Http"
+ ],
+ "mentionees": [
+ "dotnet/ncl"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Net.Security"
+ ],
+ "mentionees": [
+ "dotnet/ncl",
+ "vcsjones"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Net.Sockets"
+ ],
+ "mentionees": [
+ "dotnet/ncl"
+ ]
+ },
+ {
+ "labels": [
+ "area-Diagnostics-coreclr"
+ ],
+ "mentionees": [
+ "tommcdon"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics"
+ ],
+ "mentionees": [
+ "tommcdon"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Data"
+ ],
+ "mentionees": [
+ "roji",
+ "ajcvickers"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Data.OleDB"
+ ],
+ "mentionees": [
+ "roji",
+ "ajcvickers"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Data.Odbc"
+ ],
+ "mentionees": [
+ "roji",
+ "ajcvickers"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Data.SqlClient"
+ ],
+ "mentionees": [
+ "cheenamalhotra",
+ "david-engel"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.ComponentModel.DataAnnotations"
+ ],
+ "mentionees": [
+ "ajcvickers",
+ "bricelam",
+ "roji"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-FileSystem"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-filesystem",
+ "maryamariyan"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-HttpClientFactory"
+ ],
+ "mentionees": [
+ "dotnet/ncl"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Net.Quic"
+ ],
+ "mentionees": [
+ "dotnet/ncl"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Formats.Cbor"
+ ],
+ "mentionees": [
+ "dotnet/area-system-formats-cbor"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Formats.Asn1"
+ ],
+ "mentionees": [
+ "dotnet/area-system-formats-asn1"
+ ]
+ },
+ {
+ "labels": [
+ "area-Codegen-JIT-Mono"
+ ],
+ "mentionees": [
+ "SamMonoRT",
+ "vargaz"
+ ]
+ },
+ {
+ "labels": [
+ "area-CodeGen-LLVM-Mono"
+ ],
+ "mentionees": [
+ "SamMonoRT",
+ "vargaz",
+ "imhameed"
+ ]
+ },
+ {
+ "labels": [
+ "area-CodeGen-meta-Mono"
+ ],
+ "mentionees": [
+ "SamMonoRT",
+ "vargaz",
+ "lambdageek"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Text.Json"
+ ],
+ "mentionees": [
+ "dotnet/area-system-text-json"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Memory"
+ ],
+ "mentionees": [
+ "dotnet/area-system-memory"
+ ]
+ },
+ {
+ "labels": [
+ "area-Infrastructure-coreclr"
+ ],
+ "mentionees": [
+ "hoyosjs"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.IO"
+ ],
+ "mentionees": [
+ "dotnet/area-system-io"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.IO.Compression"
+ ],
+ "mentionees": [
+ "dotnet/area-system-io-compression"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.Process"
+ ],
+ "mentionees": [
+ "dotnet/area-system-diagnostics-process"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Console"
+ ],
+ "mentionees": [
+ "dotnet/area-system-console"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Runtime"
+ ],
+ "mentionees": [
+ "dotnet/area-system-runtime"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Threading"
+ ],
+ "mentionees": [
+ "mangod9"
+ ]
+ },
+ {
+ "labels": [
+ "area-vm-coreclr"
+ ],
+ "mentionees": [
+ "mangod9"
+ ]
+ },
+ {
+ "labels": [
+ "area-CodeGen-coreclr"
+ ],
+ "mentionees": [
+ "JulieLeeMSFT"
+ ]
+ },
+ {
+ "labels": [
+ "area-ILTools-coreclr"
+ ],
+ "mentionees": [
+ "JulieLeeMSFT"
+ ]
+ },
+ {
+ "labels": [
+ "area-ILVerification"
+ ],
+ "mentionees": [
+ "JulieLeeMSFT"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.DirectoryServices"
+ ],
+ "mentionees": [
+ "dotnet/area-system-directoryservices",
+ "jay98014"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Speech"
+ ],
+ "mentionees": [
+ "danmoseley"
+ ]
+ },
+ {
+ "labels": [
+ "area-Meta"
+ ],
+ "mentionees": [
+ "dotnet/area-meta"
+ ]
+ },
+ {
+ "labels": [
+ "area-DependencyModel"
+ ],
+ "mentionees": [
+ "dotnet/area-dependencymodel"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Caching"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-caching"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Configuration"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-configuration"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-DependencyInjection"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-dependencyinjection"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Hosting"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-hosting"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Logging"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-logging"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Options"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-options"
+ ]
+ },
+ {
+ "labels": [
+ "area-Extensions-Primitives"
+ ],
+ "mentionees": [
+ "dotnet/area-extensions-primitives"
+ ]
+ },
+ {
+ "labels": [
+ "area-Microsoft.Extensions"
+ ],
+ "mentionees": [
+ "dotnet/area-microsoft-extensions"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.ComponentModel"
+ ],
+ "mentionees": [
+ "dotnet/area-system-componentmodel"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.ComponentModel.Composition"
+ ],
+ "mentionees": [
+ "dotnet/area-system-componentmodel-composition"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Composition"
+ ],
+ "mentionees": [
+ "dotnet/area-system-composition"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.Activity"
+ ],
+ "mentionees": [
+ "dotnet/area-system-diagnostics-activity"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Globalization"
+ ],
+ "mentionees": [
+ "dotnet/area-system-globalization"
+ ]
+ },
+ {
+ "labels": [
+ "area-Microsoft.Win32"
+ ],
+ "mentionees": [
+ "dotnet/area-microsoft-win32"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.EventLog"
+ ],
+ "mentionees": [
+ "dotnet/area-system-diagnostics-eventlog"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.PerformanceCounter"
+ ],
+ "mentionees": [
+ "dotnet/area-system-diagnostics-performancecounter"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Diagnostics.TraceSource"
+ ],
+ "mentionees": [
+ "dotnet/area-system-diagnostics-tracesource"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Drawing"
+ ],
+ "mentionees": [
+ "dotnet/area-system-drawing"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Management"
+ ],
+ "mentionees": [
+ "dotnet/area-system-management"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.ServiceProcess"
+ ],
+ "mentionees": [
+ "dotnet/area-system-serviceprocess"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Configuration"
+ ],
+ "mentionees": [
+ "dotnet/area-system-configuration"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Reflection"
+ ],
+ "mentionees": [
+ "dotnet/area-system-reflection"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Reflection.Emit"
+ ],
+ "mentionees": [
+ "dotnet/area-system-reflection-emit"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Reflection.Metadata"
+ ],
+ "mentionees": [
+ "dotnet/area-system-reflection-metadata"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Resources"
+ ],
+ "mentionees": [
+ "dotnet/area-system-resources",
+ "tarekgh"
+ ]
+ },
+ {
+ "labels": [
+ "area-System.Runtime.CompilerServices"
+ ],
+ "mentionees": [
+ "dotnet/area-system-runtime-compilerservices"
+ ]
+ }
+ ],
+ "replyTemplate": "Tagging subscribers to this area: ${mentionees}\nSee info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.",
+ "enableForPullRequests": true
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "breaking-change"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "",
+ "parameters": {}
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs-breaking-change-doc-created"
+ }
+ },
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Added `needs-breaking-change-doc-created` label because this issue has the `breaking-change` label. \n\n1. [ ] Create and link to this issue a matching issue in the dotnet/docs repo using the [breaking change documentation template](https://github.com/dotnet/docs/issues/new?assignees=gewarren&labels=breaking-change%2CPri1%2Cdoc-idea&template=breaking-change.yml&title=%5BBreaking+change%5D%3A+), then remove this `needs-breaking-change-doc-created` label.\n\nTagging @dotnet/compat for awareness of the breaking change."
+ }
+ }
+ ],
+ "taskName": "Add breaking change doc label to issue"
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "breaking-change"
+ }
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs-breaking-change-doc-created"
+ }
+ },
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Added `needs-breaking-change-doc-created` label because this PR has the `breaking-change` label. \n\nWhen you commit this breaking change:\n\n1. [ ] Create and link to this PR and the issue a matching issue in the dotnet/docs repo using the [breaking change documentation template](https://github.com/dotnet/docs/issues/new?assignees=gewarren&labels=breaking-change%2CPri1%2Cdoc-idea&template=breaking-change.yml&title=%5BBreaking+change%5D%3A+), then remove this `needs-breaking-change-doc-created` label.\n2. [ ] Ask a committer to mail the `.NET Breaking Change Notification` DL.\n\nTagging @dotnet/compat for awareness of the breaking change."
+ }
+ }
+ ],
+ "taskName": "Add breaking change doc label to PR"
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 1,
+ 7,
+ 13,
+ 19
+ ],
+ "timezoneOffset": 0
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isClosed",
+ "parameters": {}
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 30
+ }
+ },
+ {
+ "name": "isUnlocked",
+ "parameters": {}
+ }
+ ],
+ "actions": [
+ {
+ "name": "lockIssue",
+ "parameters": {
+ "reason": "resolved",
+ "label": "will_lock_this"
+ }
+ }
+ ],
+ "taskName": "Lock stale issues and PR's"
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "Replace `needs more info` label with `needs further triage` label when the author comments on an issue",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "created"
+ }
+ },
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": {
+ "type": "author"
+ }
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs more info"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "needs more info"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "Remove `no recent activity` label from issues when issue is modified",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "Remove `no recent activity` label when an issue is commented on",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ],
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "taskName": "Close issues with no recent activity",
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 0,
+ 6,
+ 12,
+ 18
+ ],
+ "timezoneOffset": 0
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 14
+ }
+ }
+ ],
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "This issue will now be closed since it had been marked `no recent activity` but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days."
+ }
+ },
+ {
+ "name": "closeIssue",
+ "parameters": {}
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "taskName": "Add no recent activity label to issues",
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 4,
+ 10,
+ 16,
+ 22
+ ],
+ "timezoneOffset": 1
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isIssue",
+ "parameters": {}
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs more info"
+ }
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 14
+ }
+ },
+ {
+ "name": "noLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ],
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ },
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "This issue has been automatically marked `no recent activity` because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove `no recent activity`."
+ }
+ }
+ ]
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "InPrLabel",
+ "subCapability": "InPrLabel",
+ "version": "1.0",
+ "config": {
+ "taskName": "Add 'In-PR' label on issue when an open pull request is targeting it",
+ "inPrLabelText": "Status: In PR",
+ "fixedLabelText": "Status: Fixed",
+ "fixedLabelEnabled": false,
+ "label_inPr": "in pr"
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for linkable-framework",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "linkable-framework"
+ ],
+ "mentionees": [
+ "eerhardt",
+ "vitek-karas",
+ "LakshanF",
+ "sbomer",
+ "joperezr"
+ ]
+ }
+ ],
+ "replyTemplate": "Tagging subscribers to 'linkable-framework': ${mentionees}\nSee info in area-owners.md if you want to be subscribed.",
+ "enableForPullRequests": true
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for size-reduction",
+ "replyTemplate": "Tagging subscribers to 'size-reduction': ${mentionees}\nSee info in area-owners.md if you want to be subscribed.",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "size-reduction"
+ ],
+ "mentionees": [
+ "eerhardt",
+ "SamMonoRT",
+ "marek-safar"
+ ]
+ }
+ ],
+ "enableForPullRequests": true
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for wasm",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "arch-wasm"
+ ],
+ "mentionees": [
+ "lewing"
+ ]
+ }
+ ],
+ "replyTemplate": "Tagging subscribers to 'arch-wasm': ${mentionees}\nSee info in area-owners.md if you want to be subscribed.",
+ "enableForPullRequests": true
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for ios",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "os-ios"
+ ],
+ "mentionees": [
+ "steveisok",
+ "akoeplinger"
+ ]
+ }
+ ],
+ "enableForPullRequests": true,
+ "replyTemplate": "Tagging subscribers to 'os-ios': ${mentionees}\nSee info in area-owners.md if you want to be subscribed."
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for android",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "os-android"
+ ],
+ "mentionees": [
+ "steveisok",
+ "akoeplinger"
+ ]
+ }
+ ],
+ "enableForPullRequests": true,
+ "replyTemplate": "Tagging subscribers to 'arch-android': ${mentionees}\nSee info in area-owners.md if you want to be subscribed."
+ }
+ },
+ {
+ "taskType": "scheduled",
+ "capabilityId": "ScheduledSearch",
+ "subCapability": "ScheduledSearch",
+ "version": "1.1",
+ "config": {
+ "frequency": [
+ {
+ "weekDay": 0,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 1,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 2,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 3,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 4,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 5,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ },
+ {
+ "weekDay": 6,
+ "hours": [
+ 5,
+ 11,
+ 17,
+ 23
+ ],
+ "timezoneOffset": 0
+ }
+ ],
+ "searchTerms": [
+ {
+ "name": "isDraftPr",
+ "parameters": {
+ "value": "true"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "noActivitySince",
+ "parameters": {
+ "days": 30
+ }
+ }
+ ],
+ "taskName": "Close inactive Draft PRs",
+ "actions": [
+ {
+ "name": "closeIssue",
+ "parameters": {}
+ },
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Draft Pull Request was automatically closed for inactivity. Please [let us know](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you'd like to reopen it."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "label": "area-System.DirectoryServices",
+ "projectName": "Triage POD for Meta, Reflection, etc"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ComponentModel.Composition"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Composition"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[joperezr Pod Triage] Move issue to our pod project when a label from our area is added.",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Needs triage"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-DependencyModel"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Caching"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Configuration"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-DependencyInjection"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Hosting"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Logging"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Options"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Primitives"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ComponentModel"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Drawing"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Globalization"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Add issues to POD project",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Untriaged"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Move issues to 6.0.0 column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "6.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Active PRs"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-DependencyModel"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Caching"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Configuration"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-DependencyInjection"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Hosting"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Logging"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Options"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Extensions-Primitives"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Drawing"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ComponentModel"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Globalization"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Add PRs to project board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Active PRs"
+ }
+ },
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Active PRs"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Move issues to future milestone column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Future"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "removedFromMilestone",
+ "parameters": {
+ "milestoneName": ""
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Move issues to untriaged column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-DependencyModel"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Caching"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Configuration"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-DependencyInjection"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Hosting"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Logging"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Options"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Extensions-Primitives"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.ComponentModel"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Drawing"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Globalization"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-DependencyModel"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Caching"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Configuration"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-DependencyInjection"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Hosting"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Logging"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Options"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Extensions-Primitives"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.ComponentModel"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Drawing"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Globalization"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod triage] Remove from project",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Future"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "[joperezr Pod Triage] Move issues from Future column to Needs triage when commented on.",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Needs triage"
+ }
+ },
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Future"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "labeled"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "unlabeled"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[joperezr Pod Triage] Move issues from Future column to Needs triage when issue is changed.",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Needs triage"
+ }
+ },
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Add issues to infra POD project",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Add infrastructure issues to future column in project board",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "Future"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Add to 6.0.0 column in infrastructure project board",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "6.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "addedToMilestone",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {}
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Move to servicing column in infrastructure project",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "Servicing"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Add infrastructure PRs to Active project column",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "In Progress"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Remove PRs from Infrastructure project",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-coreclr"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-installer"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-libraries"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Infrastructure-mono"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Remove issues from infrastructure project board",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "removedFromMilestone",
+ "parameters": {}
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Move issues to Untriaged column in infrastructure project",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Microsoft.Win32"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.EventLog"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.PerformanceCounter"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.Tracing"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Management"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ServiceProcess"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh\\Viktor Pod Triage] Add untriaged issues to the pod",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": []
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh/Viktor Pod triage] Move issues to 6.0.0 milestone column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "6.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "columnName": "Active Prs",
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Microsoft.Win32"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.EventLog"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.PerformanceCounter"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Diagnostics.Tracing"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Management"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ServiceProcess"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh/Viktor Pod triage] Add PRs to project board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Active PRs"
+ }
+ },
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Active PRs"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "removedFromMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ },
+ {
+ "name": "removedFromMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh/Viktor Pod triage] Move issues to untriaged column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Untriaged"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "Future"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh/Viktor Pod triage] Move issues to future milestone column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI",
+ "columnName": "Future"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": ""
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Diagnostics.EventLog"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Diagnostics.PerformanceCounter"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Diagnostics.Tracing"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.Management"
+ }
+ },
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "area-System.ServiceProcess"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Microsoft.Win32"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Diagnostics.EventLog"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Diagnostics.PerformanceCounter"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Diagnostics.Tracing"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Management"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.ServiceProcess"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Anirudh/ViktorPod triage] Remove from project",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Issue Triage Pod for EventLog, PerformanceCounter , Tracing, ServiceProcess and WMI"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.ComponentModel.Composition"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Composition"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[joperezr Pod Triage] Move PRs to our pod project when a label from our area is added",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Triage POD for Meta, Reflection, etc",
+ "columnName": "Needs triage"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "prMatchesPattern",
+ "parameters": {
+ "matchRegex": ".*ILLink.*"
+ }
+ },
+ {
+ "name": "prMatchesPattern",
+ "parameters": {
+ "matchRegex": ".*illink.*"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "linkable-framework"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Linkable-framework workgroup] Add linkable-framework label to new Prs that touch files with *ILLink* that not have it already",
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "linkable-framework"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "prMatchesPattern",
+ "parameters": {
+ "matchRegex": ".*ILLink.*"
+ }
+ },
+ {
+ "name": "prMatchesPattern",
+ "parameters": {
+ "matchRegex": ".*illink.*"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "linkable-framework"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "synchronize"
+ }
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Linkable-framework workgroup] Add linkable-framework label to Prs that get changes pushed where they touch *ILLInk* files",
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "linkable-framework"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "dotnet-maestro[bot]"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "opened"
+ }
+ },
+ {
+ "name": "titleContains",
+ "parameters": {
+ "titlePattern": "dotnet-optimization"
+ }
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Auto-approve maestro PRs",
+ "actions": [
+ {
+ "name": "approvePullRequest",
+ "parameters": {
+ "comment": "Auto-approve dotnet-optimization PR"
+ }
+ }
+ ]
+ },
+ "disabled": true
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "opened"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "association": "OWNER",
+ "permissions": "admin"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "association": "MEMBER",
+ "permissions": "write"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "github-actions[bot]"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "dotnet-maestro[bot]"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "dotnet-maestro-bot[bot]"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "dotnet-maestro-bot"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "dotnet-maestro"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": "github-actions"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Label community PRs",
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "community-contribution"
+ }
+ }
+ ]
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": ".NET Core Diagnostics ",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Diagnostics"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Diagnostics-coreclr"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Tracing-coreclr"
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "6.0.0"
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "User Story"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "enhancement"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "feature request"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[hoyosjs/tommcdon] Add diagnostics 6.0 issues to project",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": ".NET Core Diagnostics",
+ "columnName": "6.0.0",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD."
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[safern/maryamariyan Pod Triage] Move issues to 7.0.0 column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "ML, Extensions, Globalization, etc, POD.",
+ "columnName": "7.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Infrastructure Backlog"
+ }
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "untriaged"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelRemoved",
+ "parameters": {
+ "label": "needs further triage"
+ }
+ },
+ {
+ "name": "isInMilestone",
+ "parameters": {
+ "milestoneName": "7.0.0"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "untriaged"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Viktor/safern] Add infrastructure issue to 7.0.0 column",
+ "actions": [
+ {
+ "name": "moveToProjectColumn",
+ "parameters": {
+ "projectName": "Infrastructure Backlog",
+ "columnName": "7.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "no recent activity"
+ }
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Issue cleanup notification",
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.\n\nThis process is part of the experimental [issue cleanup initiative](https://github.com/dotnet/runtime/issues/60288) we are currently trialing in a limited number of areas. Please share any feedback you might have in the linked issue."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs more info"
+ }
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Needs more info notification",
+ "actions": [
+ {
+ "name": "addReply",
+ "parameters": {
+ "comment": "This issue has been marked `needs more info` since it may be missing important information. Please refer to our [contribution guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md#writing-a-good-bug-report) for tips on how to report issues effectively."
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "taskName": "@Mention for tvos",
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "os-tvos"
+ ],
+ "mentionees": [
+ "steveisok",
+ "akoeplinger"
+ ]
+ }
+ ],
+ "enableForPullRequests": true,
+ "replyTemplate": "Tagging subscribers to 'os-tvos': ${mentionees}\nSee info in area-owners.md if you want to be subscribed."
+ }
+ },
+ {
+ "taskType": "scheduledAndTrigger",
+ "capabilityId": "IssueRouting",
+ "subCapability": "@Mention",
+ "version": "1.0",
+ "config": {
+ "labelsAndMentions": [
+ {
+ "labels": [
+ "os-maccatalyst"
+ ],
+ "mentionees": [
+ "steveisok",
+ "akoeplinger"
+ ]
+ }
+ ],
+ "replyTemplate": "Tagging subscribers to 'os-maccatalyst': ${mentionees}\nSee info in area-owners.md if you want to be subscribed.",
+ "enableForPullRequests": true,
+ "taskName": "@Mention for maccatalyst"
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestReviewResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "state": "changes_requested",
+ "permissions": "write"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "submitted"
+ }
+ },
+ {
+ "name": "isReviewState",
+ "parameters": {
+ "state": "changes_requested"
+ }
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request_review"
+ ],
+ "taskName": "PR reviews with \"changes requested\" applies the needs-author-action label",
+ "actions": [
+ {
+ "name": "addLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "synchronize"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "Pushing changes to PR branch removes the needs-author-action label",
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": {
+ "type": "author"
+ }
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "created"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "Author commenting in PR removes the needs-author-action label",
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ }
+ ]
+ },
+ "disabled": false
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestReviewResponder",
+ "version": "1.0",
+ "config": {
+ "taskName": "Author responding to a pull request review comment removes the needs-author-action label",
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isActivitySender",
+ "parameters": {
+ "user": {
+ "type": "author"
+ }
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "submitted"
+ }
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ }
+ ]
+ },
+ "actions": [
+ {
+ "name": "removeLabel",
+ "parameters": {
+ "label": "needs-author-action"
+ }
+ }
+ ],
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request_review"
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "reopened"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {}
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "isOrgProject": true,
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eric / Jeff - Issue Triage] Add new issue to Board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isCloseAndComment",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "permissions": "write"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "[Area Pod: Eric / Jeff - Issue Triage] Needs Further Triage",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eric / Jeff - Issue Triage] Remove relabeled issues",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {}
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs more info"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "api-ready-for-review"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eric / Jeff - Issue Triage] Move to Triaged Column",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - PRs] Add new PR to Board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs",
+ "columnName": "Needs Champion",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - PRs",
+ "columnName": "Needs Champion",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-Meta"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eric / Jeff - PRs] Remove relabeled PRs",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Eric / Jeff - PRs",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.RegularExpressions"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Channels"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Tasks"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "reopened"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {}
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Text.RegularExpressions"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Threading.Channels"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Threading.Tasks"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "isOrgProject": true,
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Buyaa / Jose / Steve - Issue Triage] Add new issue to Board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.RegularExpressions"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Channels"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Tasks"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isCloseAndComment",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "permissions": "write"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "[Area Pod: Buyaa / Jose / Steve - Issue Triage] Needs Further Triage",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.RegularExpressions"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Channels"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Tasks"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Buyaa / Jose / Steve - Issue Triage] Remove relabeled issues",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {}
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs more info"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "api-ready-for-review"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Buyaa / Jose / Steve - Issue Triage] Move to Triaged Column",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - PRs",
+ "columnName": "Needs Champion",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.CodeDom"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Configuration"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Emit"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Reflection.Metadata"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Resources"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Runtime.CompilerServices"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.RegularExpressions"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Channels"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Threading.Tasks"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.DirectoryServices"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Buyaa / Jose / Steve - PRs] Remove relabeled PRs",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Buyaa / Jose / Steve - PRs",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "reopened"
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInMilestone",
+ "parameters": {}
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "isOpen",
+ "parameters": {}
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "isOrgProject": true,
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - Issue Triage] Add new issue to Board",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssueCommentResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ },
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isCloseAndComment",
+ "parameters": {}
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "activitySenderHasPermissions",
+ "parameters": {
+ "permissions": "write"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issue_comment"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - Issue Triage] Needs Further Triage",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Needs Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - Issue Triage] Remove relabeled issues",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "IssuesOnlyResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Triaged"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "or",
+ "operands": [
+ {
+ "name": "addedToMilestone",
+ "parameters": {}
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "needs more info"
+ }
+ },
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "api-ready-for-review"
+ }
+ },
+ {
+ "name": "isAction",
+ "parameters": {
+ "action": "closed"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "issue",
+ "eventNames": [
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - Issue Triage] Move to Triaged Column",
+ "actions": [
+ {
+ "name": "addToProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - Issue Triage",
+ "columnName": "Triaged",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ },
+ {
+ "taskType": "trigger",
+ "capabilityId": "IssueResponder",
+ "subCapability": "PullRequestResponder",
+ "version": "1.0",
+ "config": {
+ "conditions": {
+ "operator": "and",
+ "operands": [
+ {
+ "name": "isInProjectColumn",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs",
+ "columnName": "Needs Champion",
+ "isOrgProject": true
+ }
+ },
+ {
+ "operator": "and",
+ "operands": [
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Collections"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Linq"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Text.Json"
+ }
+ }
+ ]
+ },
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.Xml"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "eventType": "pull_request",
+ "eventNames": [
+ "pull_request",
+ "issues",
+ "project_card"
+ ],
+ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi - PRs] Remove relabeled PRs",
+ "actions": [
+ {
+ "name": "removeFromProject",
+ "parameters": {
+ "projectName": "Area Pod: Eirik / Krzysztof / Layomi - PRs",
+ "isOrgProject": true
+ }
+ }
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 10a7c114340a5d..6276483bfde877 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -54,7 +54,7 @@
net$(NetCoreAppToolCurrentVersion)
$(NetCoreAppCurrentIdentifier),Version=v$(NetCoreAppToolCurrentVersion)
- 5.0
+ 6.0
$(NetCoreAppLatestStableVersion).0
net$(NetCoreAppLatestStableVersion)
@@ -278,6 +278,8 @@
preview
+
+ preview
latest
strict;nullablePublicOnly
diff --git a/docs/area-owners.md b/docs/area-owners.md
index c1d570ca21d314..70cc2e4e82fdd9 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -29,7 +29,7 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-Extensions-Caching | @ericstj | @eerhardt @maryamariyan @tarekgh | Consultants: @adamsitnik |
| area-Extensions-Configuration | @ericstj | @eerhardt @maryamariyan @tarekgh | |
| area-Extensions-DependencyInjection | @ericstj | @eerhardt @maryamariyan @tarekgh | |
-| area-Extensions-FileSystem | @jeffhandley | @adamsitnik @carlossanlop @jozkee | Consultants: @eerhardt |
+| area-Extensions-FileSystem | @jeffhandley | @adamsitnik @jozkee | Consultants: @eerhardt |
| area-Extensions-Hosting | @ericstj | @eerhardt @maryamariyan @tarekgh | |
| area-Extensions-HttpClientFactory | @karelz | @dotnet/ncl | |
| area-Extensions-Logging | @ericstj | @eerhardt @maryamariyan @tarekgh | |
@@ -44,7 +44,7 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-Infrastructure | @agocke | @jeffschwMSFT @dleeapho | |
| area-Infrastructure-coreclr | @agocke | @jeffschwMSFT @trylek | |
| area-Infrastructure-installer | @dleeapho | @dleeapho @NikolaMilosavljevic | |
-| area-Infrastructure-libraries | @ericstj | @safern | Covers:- Packaging
- Build and test infra for libraries in dotnet/runtime repo
- VS integration
|
+| area-Infrastructure-libraries | @ericstj | @carlossanlop @safern | Covers:- Packaging
- Build and test infra for libraries in dotnet/runtime repo
- VS integration
|
| area-Infrastructure-mono | @steveisok | @directhex | |
| area-Interop-coreclr | @jeffschwMSFT | @jeffschwMSFT @AaronRobinsonMSFT | |
| area-Interop-mono | @marek-safar | @lambdageek | |
@@ -52,7 +52,7 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-Microsoft.CSharp | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
| area-Microsoft.Extensions | @ericstj | @eerhardt @maryamariyan @tarekgh | |
| area-Microsoft.VisualBasic | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
-| area-Microsoft.Win32 | @ericstj | @safern | Including System.Windows.Extensions |
+| area-Microsoft.Win32 | @ericstj | @carlossanlop @safern | Including System.Windows.Extensions |
| area-NativeAOT-coreclr | @agocke | @MichalStrehovsky @jkotas | |
| area-PAL-coreclr | @mangod9 | @janvorli | |
| area-Performance-mono | @SamMonoRT | @SamMonoRT | |
@@ -66,39 +66,39 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-System.CodeDom | @ericstj | @buyaa-n @joperezr @steveharter | |
| area-System.Collections | @jeffhandley | @eiriktsarpalis @krwq @layomia | Excluded:- System.Array -> System.Runtime
Consultants: @steveharter @GrabYourPitchForks |
| area-System.ComponentModel | @ericstj | @eerhardt @maryamariyan @tarekgh | |
-| area-System.ComponentModel.Composition | @jeffhandley | @eerhardt @maryamariyan @tarekgh | |
+| area-System.ComponentModel.Composition | @ericstj | @eerhardt @maryamariyan @tarekgh | |
| area-System.ComponentModel.DataAnnotations | @ajcvickers | @lajones @ajcvickers | Included:- System.ComponentModel.Annotations
|
-| area-System.Composition | @jeffhandley | @eerhardt @maryamariyan @tarekgh | |
+| area-System.Composition | @ericstj | @eerhardt @maryamariyan @tarekgh | |
| area-System.Configuration | @ericstj | @buyaa-n @joperezr @steveharter | |
-| area-System.Console | @jeffhandley | @adamsitnik @carlossanlop @jozkee | Consultants: @GrabYourPitchForks |
-| area-System.Data | @ajcvickers | @ajcvickers @davoudeshtehari @david-engel | - Odbc, OleDb - @saurabh500
|
+| area-System.Console | @jeffhandley | @adamsitnik @jozkee | Consultants: @GrabYourPitchForks |
+| area-System.Data | @ajcvickers | @ajcvickers @davoudeshtehari @david-engel | - Odbc, OleDb - @saurabh500
|
| area-System.Data.Odbc | @ajcvickers | @ajcvickers | |
| area-System.Data.OleDB | @ajcvickers | @ajcvickers | |
-| area-System.Data.SqlClient | @David-Engel | @davoudeshtehari @david-engel @jrahnama | Archived component - limited churn/contributions (see https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient/) |
+| area-System.Data.SqlClient | @David-Engel | @davoudeshtehari @david-engel @jrahnama | Archived component - limited churn/contributions (see https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient/) |
| area-System.Diagnostics | @tommcdon | @tommcdon | |
| area-System.Diagnostics-coreclr | @tommcdon | @tommcdon | |
| area-System.Diagnostics-mono | @lewing | @thaystg @radical | |
| area-System.Diagnostics.Activity | @tommcdon | @eerhardt @maryamariyan @tarekgh | |
-| area-System.Diagnostics.EventLog | @ericstj | @safern | |
+| area-System.Diagnostics.EventLog | @ericstj | @carlossanlop @safern | |
| area-System.Diagnostics.Metric | @tommcdon | @noahfalk | |
-| area-System.Diagnostics.PerformanceCounter | @ericstj | @safern | |
-| area-System.Diagnostics.Process | @jeffhandley | @adamsitnik @carlossanlop @jozkee | |
+| area-System.Diagnostics.PerformanceCounter | @ericstj | @carlossanlop @safern | |
+| area-System.Diagnostics.Process | @jeffhandley | @adamsitnik @jozkee | |
| area-System.Diagnostics.Tracing | @tommcdon | @noahfalk @tommcdon @safern @tarekgh | Included: - System.Diagnostics.DiagnosticSource
- System.Diagnostics.TraceSource
|
-| area-System.Diagnostics.TraceSource | @ericstj | @safern | |
+| area-System.Diagnostics.TraceSource | @ericstj | @carlossanlop @safern | |
| area-System.DirectoryServices | @ericstj | @buyaa-n @joperezr @steveharter | Consultants: @BRDPM @grubioe @jay98014 |
-| area-System.Drawing | @ericstj | @safern | |
+| area-System.Drawing | @ericstj | @carlossanlop @safern | |
| area-System.Dynamic.Runtime | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
| area-System.Formats.Asn1 | @jeffhandley | @bartonjs @GrabYourPitchforks | |
| area-System.Formats.Cbor | @jeffhandley | @bartonjs @GrabYourPitchforks | Consultants: @eiriktsarpalis |
| area-System.Globalization | @ericstj | @eerhardt @maryamariyan @tarekgh | |
-| area-System.IO | @jeffhandley | @adamsitnik @carlossanlop @jozkee | |
-| area-System.IO.Compression | @jeffhandley | @adamsitnik @carlossanlop @jozkee | - Also includes System.IO.Packaging
|
+| area-System.IO | @jeffhandley | @adamsitnik @jozkee | Consultants: @carlossanlop |
+| area-System.IO.Compression | @jeffhandley | @adamsitnik @jozkee | Consultants: @carlossanlop - Also includes System.IO.Packaging
|
| area-System.IO.Pipelines | @kevinpi | @davidfowl @halter73 @jkotalik | |
| area-System.Linq | @jeffhandley | @eiriktsarpalis @krwq @layomia | |
| area-System.Linq.Expressions | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
-| area-System.Linq.Parallel | @jeffhandley | @adamsitnik @carlossanlop @jozkee | Consultants: @stephentoub @kouvel |
-| area-System.Management | @ericstj | @safern | WMI |
-| area-System.Memory | @jeffhandley | @adamsitnik @carlossanlop @jozkee | Consultants: @GrabYourPitchforks |
+| area-System.Linq.Parallel | @jeffhandley | @adamsitnik @jozkee | Consultants: @stephentoub @kouvel |
+| area-System.Management | @ericstj | @carlossanlop @safern | WMI |
+| area-System.Memory | @jeffhandley | @adamsitnik @jozkee | Consultants: @GrabYourPitchforks |
| area-System.Net | @karelz | @dotnet/ncl | Included: |
| area-System.Net.Http | @karelz | @dotnet/ncl | |
| area-System.Net.Quic | @karelz | @dotnet/ncl | |
@@ -120,7 +120,7 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-System.Security | @jeffhandley | @bartonjs @GrabYourPitchforks | |
| area-System.ServiceModel | @HongGit | @HongGit @mconnew | Repo: https://github.com/dotnet/WCF
Packages:- System.ServiceModel.Primitives
- System.ServiceModel.Http
- System.ServiceModel.NetTcp
- System.ServiceModel.Duplex
- System.ServiceModel.Security
|
| area-System.ServiceModel.Syndication | @HongGit | @StephenMolloy @HongGit | |
-| area-System.ServiceProcess | @ericstj | @safern | |
+| area-System.ServiceProcess | @ericstj | @carlossanlop @safern | |
| area-System.Speech | @danmoseley | @danmoseley | |
| area-System.Text.Encoding | @jeffhandley | @bartonjs @GrabYourPitchforks | Consultants: @tarekgh |
| area-System.Text.Encodings.Web | @jeffhandley | @bartonjs @GrabYourPitchforks | |
diff --git a/docs/design/coreclr/botr/clr-abi.md b/docs/design/coreclr/botr/clr-abi.md
index 1f65ca71bc9ce4..f7b01352de9224 100644
--- a/docs/design/coreclr/botr/clr-abi.md
+++ b/docs/design/coreclr/botr/clr-abi.md
@@ -109,7 +109,7 @@ ARM64-only: When a method returns a structure that is larger than 16 bytes the c
*Calli Pinvoke* - The VM wants the address of the PInvoke in (AMD64) `R10` / (ARM) `R12` / (ARM64) `R14` (In the JIT: `REG_PINVOKE_TARGET_PARAM`), and the signature (the pinvoke cookie) in (AMD64) `R11` / (ARM) `R4` / (ARM64) `R15` (in the JIT: `REG_PINVOKE_COOKIE_PARAM`).
-*Normal PInvoke* - The VM shares IL stubs based on signatures, but wants the right method to show up in call stack and exceptions, so the MethodDesc for the exact PInvoke is passed in the (x86) `EAX` / (AMD64) `R10` / (ARM, ARM64) `R12` (in the JIT: `REG_SECRET_STUB_PARAM`). Then in the IL stub, when the JIT gets `CORJIT_FLG_PUBLISH_SECRET_PARAM`, it must move the register into a compiler temp. The value is returned for the intrinsic `CORINFO_INTRINSIC_StubHelpers_GetStubContext`, and the address of that location is returned for `CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr`.
+*Normal PInvoke* - The VM shares IL stubs based on signatures, but wants the right method to show up in call stack and exceptions, so the MethodDesc for the exact PInvoke is passed in the (x86) `EAX` / (AMD64) `R10` / (ARM, ARM64) `R12` (in the JIT: `REG_SECRET_STUB_PARAM`). Then in the IL stub, when the JIT gets `CORJIT_FLG_PUBLISH_SECRET_PARAM`, it must move the register into a compiler temp. The value is returned for the intrinsic `NI_System_StubHelpers_GetStubContext`.
# PInvokes
diff --git a/docs/infra/automation.md b/docs/infra/automation.md
new file mode 100644
index 00000000000000..23af9d9e4a2088
--- /dev/null
+++ b/docs/infra/automation.md
@@ -0,0 +1,7 @@
+## Automation
+
+### Fabric Bot
+
+This repository uses Fabric Bot to automate issue and pull request management. All automation rules are defined in the [`.github/fabricbot.json`](.github/fabricbot.json) file.
+
+At this moment Fabric Bot has not published a JSON schema for the configuration format. In order to make changes to the configuration file, you should use the [`Fabric Bot portal`](https://portal.fabricbot.ms/bot/) to load the configuration file via the "Import Configuration" option and make changes using the editor. You need to be signed out from the portal in order for this option to appear.
diff --git a/docs/workflow/building/mono/README.md b/docs/workflow/building/mono/README.md
index 0b5c4701d20601..56c95551f5eba8 100644
--- a/docs/workflow/building/mono/README.md
+++ b/docs/workflow/building/mono/README.md
@@ -33,6 +33,15 @@ build.cmd mono
```
When the build completes, product binaries will be dropped in the `artifacts\bin\mono\..` folder.
+If you want to skip restoring nuget packages, when only making change to mono, you want to use this command:
+```bash
+./build.sh mono --build
+```
+or on Windows,
+```cmd
+build.cmd mono --build
+```
+
### Useful Build Arguments
Here are a list of build arguments that may be of use:
diff --git a/docs/workflow/requirements/windows-requirements.md b/docs/workflow/requirements/windows-requirements.md
index 402610a6253448..6e32c5f1d45a6d 100644
--- a/docs/workflow/requirements/windows-requirements.md
+++ b/docs/workflow/requirements/windows-requirements.md
@@ -37,7 +37,7 @@ Visual Studio 2022 installation process:
A `.vsconfig` file is included in the root of the dotnet/runtime repository that includes all components needed to build the dotnet/runtime repository. You can [import `.vsconfig` in your Visual Studio installer](https://docs.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2022#import-a-configuration) to install all necessary components. You may get a message saying 'Microsoft.Net.Component.4.5.2.TargetingPack has no matching workload or component found'. This is not an issue as long as you have a newer targeting pack installed.
-Visual Studio 2022 Preview 4 or later is required.
+Visual Studio 2022 or later is required.
## Build Tools
diff --git a/docs/workflow/testing/libraries/testing-apple.md b/docs/workflow/testing/libraries/testing-apple.md
index c303fc737362d2..0ce42742e9c710 100644
--- a/docs/workflow/testing/libraries/testing-apple.md
+++ b/docs/workflow/testing/libraries/testing-apple.md
@@ -108,6 +108,10 @@ To build for AOT only mode, add `/p:RunAOTCompilation=true /p:MonoEnableInterpre
To build for AOT-LLVM mode, add `/p:RunAOTCompilation=true /p:MonoEnableInterpreter=false /p:MonoEnableLLVM=true` to a build command.
+4. App Sandbox
+
+To build the test app bundle with the App Sandbox entitlement, add `/p:EnableAppSandbox=true` to a build command.
+
### Test App Design
iOS/tvOS `*.app` (or `*.ipa`) is basically a simple [ObjC app](https://github.com/dotnet/runtime/blob/main/src/tasks/AppleAppBuilder/Templates/main-console.m) that inits the Mono Runtime. This Mono Runtime starts a simple xunit test
runner called XHarness.TestRunner (see https://github.com/dotnet/xharness) which runs tests for all `*.Tests.dll` libs in the bundle. There is also XHarness.CLI tool to deploy `*.app` and `*.ipa` to a target (device or simulator) and listens for logs via network sockets.
diff --git a/docs/workflow/testing/mono/testing.md b/docs/workflow/testing/mono/testing.md
index 14d141e529a3ca..7d34ee1a7b0380 100644
--- a/docs/workflow/testing/mono/testing.md
+++ b/docs/workflow/testing/mono/testing.md
@@ -7,10 +7,10 @@ Before running tests, [build Mono](../../building/mono/README.md) using the desi
To build the runtime tests for Mono JIT or interpreter:
-1. Build CoreCLR - the `clr.native` subset is enough but you can build the whole thing, optionally. From the `$(REPO_ROOT)`:
+1. Build test host (corerun) - From the `$(REPO_ROOT)`:
```
-./build.sh clr.native -c
+./build.sh clr.hosts -c
```
2. Build the tests (in `$(REPO_ROOT)/src/tests`)
@@ -26,25 +26,23 @@ For example: `./build.sh excludemonofailures release -test:JIT/opt/InstructionCo
Run individual test:
```
-cd src/mono
-make run-tests-coreclr CoreClrTest="bash ../../artifacts/tests/coreclr/OSX.x64.Release/JIT/opt/InstructionCombining/DivToMul/DivToMul.sh"
+bash ./artifacts/tests/coreclr/OSX.x64.Release/JIT/opt/InstructionCombining/DivToMul/DivToMul.sh -coreroot=`pwd`/artifacts/tests/coreclr/OSX.x64.Release/Tests/Core_Root
```
-Run all tests:
+Run all built tests:
```
-cd src/mono
-make run-tests-coreclr-all
+./run.sh
```
To debug a single test with `lldb`:
-1. Run the test at least once normally (or manually run the `mono.proj` `PatchCoreClrCoreRoot` target)
-2. Run the shell script for the test case manually:
+1. Run the shell script for the test case manually with the `-debug` option:
```
bash ./artifacts/tests/coreclr/OSX.x64.Release/JIT/opt/InstructionCombining/DivToMul/DivToMul.sh -coreroot=`pwd`/artifacts/tests/coreclr/OSX.x64.Release/Tests/Core_Root -debug=/usr/bin/lldb
```
-3. In LLDB add the debug symbols for mono: `add-dsym /libcoreclr.dylib.dwarf`
-4. Run/debug the test
+2. In LLDB add the debug symbols for mono: `add-dsym /libcoreclr.dylib.dwarf`
+3. Run/debug the test
+
### WebAssembly:
Build the runtime tests for WebAssembly
diff --git a/eng/ApiCompatExcludeAttributes.txt b/eng/ApiCompatExcludeAttributes.txt
index 16db9ad94cda54..19475f50297f8a 100644
--- a/eng/ApiCompatExcludeAttributes.txt
+++ b/eng/ApiCompatExcludeAttributes.txt
@@ -1,2 +1,3 @@
T:System.CLSCompliantAttribute
T:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute
+T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 65da9d8861bd68..b76d849cf4cc26 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -100,6 +100,7 @@
+
@@ -164,6 +165,10 @@
+
+ $(ClrRuntimeBuildSubsets);ClrHostsSubset=true
+
+
$(ClrRuntimeBuildSubsets);ClrRuntimeSubset=true
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index d4afac7bd540bf..a677399625acac 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,8 +1,8 @@
-
+
https://github.com/dotnet/icu
- c454e00c63464ff6b599f23448bcc0a0c9fbac5f
+ c2e633bfc491d2b9dc5e49d2ffe3de9b4b5359d0
https://github.com/dotnet/msquic
@@ -18,153 +18,157 @@
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
https://github.com/microsoft/vstest
140434f7109d357d0158ade9e5164a4861513965
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
-
+
+ https://github.com/dotnet/runtime-assets
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
+
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
-
+
https://github.com/dotnet/llvm-project
- 2e69189f031e16ffb36167d89a658e14cbdba099
+ 45004b720a726e3283dc241136384198a823312d
https://github.com/dotnet/runtime
@@ -202,17 +206,17 @@
https://github.com/dotnet/linker
4e77a943d360a5afea00de7b8a2d0ba2c721223f
-
+
https://github.com/dotnet/xharness
- d27acf37630aa2a03824b698aa51356e47f902c0
+ 5898930d87e4acca8fbcea5f38f08c967a506f79
-
+
https://github.com/dotnet/xharness
- d27acf37630aa2a03824b698aa51356e47f902c0
+ 5898930d87e4acca8fbcea5f38f08c967a506f79
-
+
https://github.com/dotnet/arcade
- 59775387deb609d7c62f9e713d133c34ba28ffcd
+ 05a63c6bae31f97583d35f5a16e1bd8f41a1d094
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
@@ -230,13 +234,13 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
91d6b3c1f51888d166701510189505f35714665c
-
+
https://github.com/dotnet/hotreload-utils
- 49922f7ec53df036084899e597f3c94627d709eb
+ 5add30ce9477193614865f98c811dc4001134308
-
+
https://github.com/dotnet/runtime-assets
- 6003aa6296ad2bebdf8147de94afbea9b5f16264
+ 658e482c4af9a16cbe9ea0fae4c6e4281f1521b6
https://github.com/dotnet/roslyn-analyzers
diff --git a/eng/Versions.props b/eng/Versions.props
index 6af39feabfeb67..cb1a36cd3a9131 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -54,21 +54,21 @@
2.0.0-alpha.1.21525.11
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 2.5.1-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
- 7.0.0-beta.21602.3
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 2.5.1-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
+ 7.0.0-beta.21609.2
6.0.0-preview.1.102
@@ -118,17 +118,18 @@
4.5.0
7.0.0-alpha.1.21576.4
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
- 7.0.0-beta.21602.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
+ 7.0.0-beta.21603.1
1.0.0-prerelease.21577.2
1.0.0-prerelease.21577.2
@@ -151,9 +152,9 @@
1.0.1-prerelease-00006
16.9.0-preview-20201201-01
- 1.0.0-prerelease.21602.2
- 1.0.0-prerelease.21602.2
- 1.0.2-alpha.0.21579.1
+ 1.0.0-prerelease.21609.1
+ 1.0.0-prerelease.21609.1
+ 1.0.2-alpha.0.21606.2
2.4.2-pre.9
2.4.2
1.3.0
@@ -169,18 +170,18 @@
7.0.100-1.21601.5
$(MicrosoftNETILLinkTasksVersion)
- 7.0.0-alpha.1.21579.1
+ 7.0.0-alpha.1.21606.1
7.0.0-alpha.1.21529.3
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
- 11.1.0-alpha.1.21579.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
+ 11.1.0-alpha.1.21606.1
7.0.0-alpha.1.21601.1
$(MicrosoftNETWorkloadEmscriptenManifest70100Version)
diff --git a/eng/common/cross/armv6/sources.list.buster b/eng/common/cross/armv6/sources.list.buster
new file mode 100644
index 00000000000000..f27fc4fb346b6c
--- /dev/null
+++ b/eng/common/cross/armv6/sources.list.buster
@@ -0,0 +1,2 @@
+deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
+deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
index 6fa2c8aa5511dd..5102245b7b5e3f 100755
--- a/eng/common/cross/build-rootfs.sh
+++ b/eng/common/cross/build-rootfs.sh
@@ -99,6 +99,15 @@ while :; do
__AlpineArch=armv7
__QEMUArch=arm
;;
+ armv6)
+ __BuildArch=armv6
+ __UbuntuArch=armhf
+ __QEMUArch=arm
+ __UbuntuRepo="http://raspbian.raspberrypi.org/raspbian/"
+ __CodeName=buster
+ __LLDB_Package="liblldb-6.0-dev"
+ __Keyring="/usr/share/keyrings/raspbian-archive-keyring.gpg"
+ ;;
arm64)
__BuildArch=arm64
__UbuntuArch=arm64
@@ -236,6 +245,12 @@ while :; do
shift
done
+if [ -e "$__Keyring" ]; then
+ __Keyring="--keyring=$__Keyring"
+else
+ __Keyring=""
+fi
+
if [ "$__BuildArch" == "armel" ]; then
__LLDB_Package="lldb-3.5-dev"
fi
@@ -337,7 +352,7 @@ elif [[ "$__CodeName" == "illumos" ]]; then
wget -P "$__RootfsDir"/usr/include/netpacket https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/inet/sockmods/netpacket/packet.h
wget -P "$__RootfsDir"/usr/include/sys https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/sys/sdt.h
elif [[ -n $__CodeName ]]; then
- qemu-debootstrap --arch $__UbuntuArch $__CodeName $__RootfsDir $__UbuntuRepo
+ qemu-debootstrap $__Keyring --arch $__UbuntuArch $__CodeName $__RootfsDir $__UbuntuRepo
cp $__CrossDir/$__BuildArch/sources.list.$__CodeName $__RootfsDir/etc/apt/sources.list
chroot $__RootfsDir apt-get update
chroot $__RootfsDir apt-get -f -y install
diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml
index 8128f2c357052c..8cf772b3cbf812 100644
--- a/eng/common/templates/job/execute-sdl.yml
+++ b/eng/common/templates/job/execute-sdl.yml
@@ -51,14 +51,9 @@ jobs:
value: ${{ parameters.AzDOPipelineId }}
- name: AzDOBuildId
value: ${{ parameters.AzDOBuildId }}
- # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
- # sync with the packages.config file.
- - name: DefaultGuardianVersion
- value: 0.109.0
+ - template: /eng/common/templates/variables/sdl-variables.yml
- name: GuardianVersion
value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }}
- - name: GuardianPackagesConfigFile
- value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
pool:
vmImage: windows-2019
steps:
@@ -125,57 +120,11 @@ jobs:
displayName: Extract Archive Artifacts
continueOnError: ${{ parameters.sdlContinueOnError }}
- - ${{ if ne(parameters.overrideGuardianVersion, '') }}:
- - powershell: |
- $content = Get-Content $(GuardianPackagesConfigFile)
-
- Write-Host "packages.config content was:`n$content"
-
- $content = $content.Replace('$(DefaultGuardianVersion)', '$(GuardianVersion)')
- $content | Set-Content $(GuardianPackagesConfigFile)
-
- Write-Host "packages.config content updated to:`n$content"
- displayName: Use overridden Guardian version ${{ parameters.overrideGuardianVersion }}
-
- - task: NuGetToolInstaller@1
- displayName: 'Install NuGet.exe'
- - task: NuGetCommand@2
- displayName: 'Install Guardian'
- inputs:
- restoreSolution: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
- feedsToUse: config
- nugetConfigPath: $(Build.SourcesDirectory)\eng\common\sdl\NuGet.config
- externalFeedCredentials: GuardianConnect
- restoreDirectory: $(Build.SourcesDirectory)\.packages
-
- - ${{ if ne(parameters.overrideParameters, '') }}:
- - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }}
- displayName: Execute SDL
- continueOnError: ${{ parameters.sdlContinueOnError }}
- - ${{ if eq(parameters.overrideParameters, '') }}:
- - powershell: ${{ parameters.executeAllSdlToolsScript }}
- -GuardianPackageName Microsoft.Guardian.Cli.$(GuardianVersion)
- -NugetPackageDirectory $(Build.SourcesDirectory)\.packages
- -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw)
- ${{ parameters.additionalParameters }}
- displayName: Execute SDL
- continueOnError: ${{ parameters.sdlContinueOnError }}
-
- - ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}:
- # We want to publish the Guardian results and configuration for easy diagnosis. However, the
- # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default
- # tooling files. Some of these files are large and aren't useful during an investigation, so
- # exclude them by simply deleting them before publishing. (As of writing, there is no documented
- # way to selectively exclude a dir from the pipeline artifact publish task.)
- - task: DeleteFiles@1
- displayName: Delete Guardian dependencies to avoid uploading
- inputs:
- SourceFolder: $(Agent.BuildDirectory)/.gdn
- Contents: |
- c
- i
- condition: succeededOrFailed()
- - publish: $(Agent.BuildDirectory)/.gdn
- artifact: GuardianConfiguration
- displayName: Publish GuardianConfiguration
- condition: succeededOrFailed()
+ - template: /eng/common/templates/steps/execute-sdl.yml
+ parameters:
+ overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }}
+ executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }}
+ overrideParameters: ${{ parameters.overrideParameters }}
+ additionalParameters: ${{ parameters.additionalParameters }}
+ publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }}
+ sdlContinueOnError: ${{ parameters.sdlContinueOnError }}
diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml
new file mode 100644
index 00000000000000..7b8ee18a28d7e7
--- /dev/null
+++ b/eng/common/templates/steps/execute-sdl.yml
@@ -0,0 +1,68 @@
+parameters:
+ overrideGuardianVersion: ''
+ executeAllSdlToolsScript: ''
+ overrideParameters: ''
+ additionalParameters: ''
+ publishGuardianDirectoryToPipeline: false
+ sdlContinueOnError: false
+ condition: ''
+
+steps:
+- ${{ if ne(parameters.overrideGuardianVersion, '') }}:
+ - powershell: |
+ $content = Get-Content $(GuardianPackagesConfigFile)
+
+ Write-Host "packages.config content was:`n$content"
+
+ $content = $content.Replace('$(DefaultGuardianVersion)', '$(GuardianVersion)')
+ $content | Set-Content $(GuardianPackagesConfigFile)
+
+ Write-Host "packages.config content updated to:`n$content"
+ displayName: Use overridden Guardian version ${{ parameters.overrideGuardianVersion }}
+
+- task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+- task: NuGetCommand@2
+ displayName: 'Install Guardian'
+ inputs:
+ restoreSolution: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
+ feedsToUse: config
+ nugetConfigPath: $(Build.SourcesDirectory)\eng\common\sdl\NuGet.config
+ externalFeedCredentials: GuardianConnect
+ restoreDirectory: $(Build.SourcesDirectory)\.packages
+
+- ${{ if ne(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }}
+ displayName: Execute SDL
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+ condition: ${{ parameters.condition }}
+
+- ${{ if eq(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }}
+ -GuardianPackageName Microsoft.Guardian.Cli.$(GuardianVersion)
+ -NugetPackageDirectory $(Build.SourcesDirectory)\.packages
+ -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw)
+ ${{ parameters.additionalParameters }}
+ displayName: Execute SDL
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+ condition: ${{ parameters.condition }}
+
+- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}:
+ # We want to publish the Guardian results and configuration for easy diagnosis. However, the
+ # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default
+ # tooling files. Some of these files are large and aren't useful during an investigation, so
+ # exclude them by simply deleting them before publishing. (As of writing, there is no documented
+ # way to selectively exclude a dir from the pipeline artifact publish task.)
+ - task: DeleteFiles@1
+ displayName: Delete Guardian dependencies to avoid uploading
+ inputs:
+ SourceFolder: $(Agent.BuildDirectory)/.gdn
+ Contents: |
+ c
+ i
+ condition: succeededOrFailed()
+ - publish: $(Agent.BuildDirectory)/.gdn
+ artifact: GuardianConfiguration
+ displayName: Publish GuardianConfiguration
+ condition: succeededOrFailed()
\ No newline at end of file
diff --git a/eng/common/templates/variables/sdl-variables.yml b/eng/common/templates/variables/sdl-variables.yml
new file mode 100644
index 00000000000000..dbdd66d4a4b3a0
--- /dev/null
+++ b/eng/common/templates/variables/sdl-variables.yml
@@ -0,0 +1,7 @@
+variables:
+# The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
+# sync with the packages.config file.
+- name: DefaultGuardianVersion
+ value: 0.109.0
+- name: GuardianPackagesConfigFile
+ value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
\ No newline at end of file
diff --git a/eng/generators.targets b/eng/generators.targets
index 13926ce90bd7ed..4c32554b5e2195 100644
--- a/eng/generators.targets
+++ b/eng/generators.targets
@@ -20,13 +20,15 @@
('@(Reference)' != ''
and @(Reference->AnyHaveMetadataValue('Identity', 'System.Runtime.InteropServices')))
or ('@(ProjectReference)' != ''
- and @(ProjectReference->AnyHaveMetadataValue('Identity', '$(CoreLibProject)'))))" />
+ and @(ProjectReference->AnyHaveMetadataValue('Identity', '$(CoreLibProject)')))
+ or ('$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'
+ and '$(DisableImplicitAssemblyReferences)' == 'false'))" />
+ and ('$(TargetFrameworkIdentifier)' == '.NETStandard' or '$(TargetFrameworkIdentifier)' == '.NETFramework' or ('$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '$(NetCoreAppCurrentVersion)'))))" />
diff --git a/eng/packaging.targets b/eng/packaging.targets
index 7f9707ab8d8148..6d2bbce10da346 100644
--- a/eng/packaging.targets
+++ b/eng/packaging.targets
@@ -22,19 +22,26 @@
'$(IsRIDSpecificProject)' == 'true') and
'$(PreReleaseVersionLabel)' != 'servicing' and
'$(GitHubRepositoryName)' != 'runtimelab'">true
+ false
$(XmlDocFileRoot)1033\$(AssemblyName).xml
true
-
+
+
+ 0
+
- $(MajorVersion).$(MinorVersion).$(ServicingVersion)
+ $(MajorVersion).$(MinorVersion).$(ServicingVersion)
+ $(Version)-$(VersionSuffix)
<_IsWindowsDesktopApp Condition="$(WindowsDesktopCoreAppLibrary.Contains('$(AssemblyName);'))">true
<_IsAspNetCoreApp Condition="$(AspNetCoreAppLibrary.Contains('$(AssemblyName);'))">true
- <_AssemblyInTargetingPack Condition="'$(IsNETCoreAppSrc)' == 'true' or '$(_IsAspNetCoreApp)' == 'true' or '$(_IsWindowsDesktopApp)' == 'true'">true
+ <_AssemblyInTargetingPack Condition="('$(IsNETCoreAppSrc)' == 'true' or '$(_IsAspNetCoreApp)' == 'true' or '$(_IsWindowsDesktopApp)' == 'true') and '$(TargetFrameworkIdentifier)' != '.NETFramework'">true
- $(MajorVersion).$(MinorVersion).0.$(ServicingVersion)
+ $(MajorVersion).$(MinorVersion).0.$(ServicingVersion)
@@ -246,9 +253,15 @@
+
+
+
+
diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml
index 1c7d6490df5f6b..05a6bc7c4a63c4 100644
--- a/eng/pipelines/common/xplat-setup.yml
+++ b/eng/pipelines/common/xplat-setup.yml
@@ -128,7 +128,7 @@ jobs:
# OSX Build Pool (we don't have on-prem OSX BuildPool
${{ if in(parameters.osGroup, 'OSX', 'MacCatalyst', 'iOS', 'iOSSimulator', 'tvOS', 'tvOSSimulator') }}:
- vmImage: 'macOS-10.15'
+ vmImage: 'macOS-11'
# Official Build Windows Pool
${{ if and(eq(parameters.osGroup, 'windows'), ne(variables['System.TeamProject'], 'public')) }}:
diff --git a/eng/pipelines/coreclr/perf.yml b/eng/pipelines/coreclr/perf.yml
index 0e274b0d899cab..ec233f348b0ecb 100644
--- a/eng/pipelines/coreclr/perf.yml
+++ b/eng/pipelines/coreclr/perf.yml
@@ -239,7 +239,7 @@ jobs:
runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml
logicalmachine: 'perfpixel4a'
- # run mono and maui iOS scenarios
+ # run mono iOS scenarios and maui iOS scenarios
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml
@@ -382,7 +382,7 @@ jobs:
runJobTemplate: /eng/pipelines/coreclr/templates/run-performance-job.yml
logicalmachine: 'perftiger'
-# run coreclr perftiger microbenchmarks pgo perf jobs
+ # run coreclr perftiger microbenchmarks pgo perf jobs
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml
diff --git a/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
index 3d5d83b6dadc88..6e8ace4e7935c2 100644
--- a/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
+++ b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
@@ -23,6 +23,32 @@ steps:
- script: make run MONO_ARCH=arm64 DEPLOY_AND_RUN=false
workingDirectory: $(Build.SourcesDirectory)/src/mono/sample/Android
displayName: Build HelloAndroid sample app
+ - template: /eng/pipelines/common/upload-artifact-step.yml
+ parameters:
+ rootFolder: $(Build.SourcesDirectory)/artifacts/bin/AndroidSampleApp/arm64/Release/android-arm64/publish/apk/bin/HelloAndroid.apk
+ includeRootFolder: true
+ displayName: Android Mono Artifacts
+ artifactName: AndroidMonoarm64
+ archiveExtension: '.tar.gz'
+ archiveType: tar
+ tarCompression: gz
+ - script: rm -r -f $(Build.SourcesDirectory)/artifacts/bin/AndroidSampleApp
+ workingDirectory: $(Build.SourcesDirectory)/artifacts/bin
+ displayName: clean bindir
+ - script: make run MONO_ARCH=arm64 DEPLOY_AND_RUN=false RUNTIME_COMPONENTS=diagnostics_tracing
+ workingDirectory: $(Build.SourcesDirectory)/src/mono/sample/Android
+ displayName: Build HelloAndroid sample app
+ - script: mv $(Build.SourcesDirectory)/artifacts/bin/AndroidSampleApp/arm64/Release/android-arm64/publish/apk/bin/HelloAndroid.apk $(Build.SourcesDirectory)/artifacts/bin/AndroidSampleApp/arm64/Release/android-arm64/publish/apk/bin/HelloAndroidWithDiag.apk
+ - template: /eng/pipelines/common/upload-artifact-step.yml
+ parameters:
+ rootFolder: $(Build.SourcesDirectory)/artifacts/bin/AndroidSampleApp/arm64/Release/android-arm64/publish/apk/bin/HelloAndroidWithDiag.apk
+ includeRootFolder: true
+ displayName: Android Mono Artifacts With Diag
+ artifactName: AndroidMonoWithDiagarm64
+ archiveExtension: '.tar.gz'
+ archiveType: tar
+ tarCompression: gz
+
- ${{ if eq(parameters.osGroup, 'iOS') }}:
- script: make build-appbundle TARGET=iOS MONO_ARCH=arm64 MONO_CONFIG=Release AOT=True USE_LLVM=False DEPLOY_AND_RUN=false
env:
@@ -37,13 +63,13 @@ steps:
artifactName: ${{ parameters.artifactName }}
- template: /eng/pipelines/common/upload-artifact-step.yml
parameters:
- rootFolder: $(Build.SourcesDirectory)/src/mono/sample/iOS/bin/ios-arm64/publish/app/HelloiOS/Release-iphoneos/HelloiOS.app
- includeRootFolder: true
- displayName: iOS Sample App NoLLVM
- artifactName: iOSSampleAppNoLLVM
- archiveExtension: '.tar.gz'
- archiveType: tar
- tarCompression: gz
+ rootFolder: $(Build.SourcesDirectory)/src/mono/sample/iOS/bin/ios-arm64/publish/app/HelloiOS/Release-iphoneos/HelloiOS.app
+ includeRootFolder: true
+ displayName: iOS Sample App NoLLVM
+ artifactName: iOSSampleAppNoLLVM
+ archiveExtension: '.tar.gz'
+ archiveType: tar
+ tarCompression: gz
- script: rm -r -f $(Build.SourcesDirectory)/src/mono/sample/iOS/bin
workingDirectory: $(Build.SourcesDirectory)/src/mono/sample/iOS
displayName: Clean bindir
@@ -60,31 +86,11 @@ steps:
artifactName: ${{ parameters.artifactName }}
- template: /eng/pipelines/common/upload-artifact-step.yml
parameters:
- rootFolder: $(Build.SourcesDirectory)/src/mono/sample/iOS/bin/ios-arm64/publish/app/HelloiOS/Release-iphoneos/HelloiOS.app
- includeRootFolder: true
- displayName: iOS Sample App LLVM
- artifactName: iOSSampleAppLLVM
- archiveExtension: '.tar.gz'
- archiveType: tar
- tarCompression: gz
+ rootFolder: $(Build.SourcesDirectory)/src/mono/sample/iOS/bin/ios-arm64/publish/app/HelloiOS/Release-iphoneos/HelloiOS.app
+ includeRootFolder: true
+ displayName: iOS Sample App LLVM
+ artifactName: iOSSampleAppLLVM
+ archiveExtension: '.tar.gz'
+ archiveType: tar
+ tarCompression: gz
- - template: /eng/pipelines/common/upload-artifact-step.yml
- parameters:
- osGroup: ${{ parameters.osGroup }}
- osSubgroup: ${{ parameters.osSubgroup }}
- archType: ${{ parameters.archType }}
- buildConfig: ${{ parameters.buildConfig }}
- runtimeFlavor: ${{ parameters.runtimeFlavor }}
- helixQueues: ${{ parameters.helixQueues }}
- targetRid: ${{ parameters.targetRid }}
- nameSuffix: ${{ parameters.nameSuffix }}
- platform: ${{ parameters.platform }}
- shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
- rootFolder: ${{ parameters.rootFolder }}
- includeRootFolder: ${{ parameters.includeRootFolder }}
- displayName: ${{ parameters.displayName }}
- artifactName: ${{ parameters.artifactName }}
- archiveExtension: ${{ parameters.archiveExtension }}
- archiveType: ${{ parameters.archiveType }}
- tarCompression: ${{ parameters.tarCompression }}
-
diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml
index 50941e60f1c5f5..dd1ff0ebd3b242 100644
--- a/eng/pipelines/coreclr/templates/perf-job.yml
+++ b/eng/pipelines/coreclr/templates/perf-job.yml
@@ -154,11 +154,11 @@ jobs:
- ${{ if eq(parameters.runtimeType, 'AndroidMono')}}:
- template: /eng/pipelines/common/download-artifact-step.yml
parameters:
- unpackFolder: $(Build.SourcesDirectory)
+ unpackFolder: $(Build.SourcesDirectory)/androidHelloWorld
cleanUnpackFolder: false
artifactFileName: 'AndroidMonoarm64.tar.gz'
artifactName: 'AndroidMonoarm64'
- displayName: 'Mono Android runtime'
+ displayName: 'Mono Android HelloWorld'
- template: /eng/pipelines/common/download-artifact-step.yml
parameters:
unpackFolder: $(Build.SourcesDirectory)
@@ -166,8 +166,14 @@ jobs:
artifactFileName: 'MauiAndroidApp.tar.gz'
artifactName: 'MauiAndroidApp'
displayName: 'Maui Android App'
-
-
+ - template: /eng/pipelines/common/download-artifact-step.yml
+ parameters:
+ unpackFolder: $(Build.SourcesDirectory)/androidHelloWorldWithDiag
+ cleanUnpackFolder: false
+ artifactFileName: 'AndroidMonoWithDiagarm64.tar.gz'
+ artifactName: 'AndroidMonoWithDiagarm64'
+ displayName: 'Mono Android Diagnostic Helloworld'
+
# Download iOSMono tests and MauiiOS/MacCatalyst
- ${{ if eq(parameters.runtimeType, 'iOSMono') }}:
- template: /eng/pipelines/common/download-artifact-step.yml
diff --git a/eng/pipelines/coreclr/templates/run-scenarios-job.yml b/eng/pipelines/coreclr/templates/run-scenarios-job.yml
index edaf1f485fc955..ab713b3c02175b 100644
--- a/eng/pipelines/coreclr/templates/run-scenarios-job.yml
+++ b/eng/pipelines/coreclr/templates/run-scenarios-job.yml
@@ -118,26 +118,26 @@ jobs:
displayName: Copy scenario support files (Linux)
condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))
# build Startup
- - script: $(PayloadDirectory)\dotnet\dotnet.exe publish -c Release -o $(WorkItemDirectory)\Startup -f netcoreapp3.1 -r win-$(Architecture) $(PerformanceDirectory)\src\tools\ScenarioMeasurement\Startup\Startup.csproj
+ - script: $(PayloadDirectory)\dotnet\dotnet.exe publish -c Release -o $(WorkItemDirectory)\Startup -f net6.0 -r win-$(Architecture) $(PerformanceDirectory)\src\tools\ScenarioMeasurement\Startup\Startup.csproj
displayName: Build Startup tool (Windows)
env:
- PERFLAB_TARGET_FRAMEWORKS: netcoreapp3.1
+ PERFLAB_TARGET_FRAMEWORKS: net6.0
condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'))
- - script: $(PayloadDirectory)/dotnet/dotnet publish -c Release -o $(WorkItemDirectory)/startup -f netcoreapp3.1 -r linux-$(Architecture) $(PerformanceDirectory)/src/tools/ScenarioMeasurement/Startup/Startup.csproj
+ - script: $(PayloadDirectory)/dotnet/dotnet publish -c Release -o $(WorkItemDirectory)/startup -f net6.0 -r linux-$(Architecture) $(PerformanceDirectory)/src/tools/ScenarioMeasurement/Startup/Startup.csproj
displayName: Build Startup tool (Linux)
env:
- PERFLAB_TARGET_FRAMEWORKS: netcoreapp3.1
+ PERFLAB_TARGET_FRAMEWORKS: net6.0
condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))
# build SizeOnDisk
- - script: $(PayloadDirectory)\dotnet\dotnet.exe publish -c Release -o $(WorkItemDirectory)\SOD -f netcoreapp3.1 -r win-$(Architecture) $(PerformanceDirectory)\src\tools\ScenarioMeasurement\SizeOnDisk\SizeOnDisk.csproj
+ - script: $(PayloadDirectory)\dotnet\dotnet.exe publish -c Release -o $(WorkItemDirectory)\SOD -f net6.0 -r win-$(Architecture) $(PerformanceDirectory)\src\tools\ScenarioMeasurement\SizeOnDisk\SizeOnDisk.csproj
displayName: Build SizeOnDisk tool (Windows)
env:
- PERFLAB_TARGET_FRAMEWORKS: netcoreapp3.1
+ PERFLAB_TARGET_FRAMEWORKS: net6.0
condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'))
- - script: $(PayloadDirectory)/dotnet/dotnet publish -c Release -o $(WorkItemDirectory)/SOD -f netcoreapp3.1 -r linux-$(Architecture) $(PerformanceDirectory)/src/tools/ScenarioMeasurement/SizeOnDisk/SizeOnDisk.csproj
+ - script: $(PayloadDirectory)/dotnet/dotnet publish -c Release -o $(WorkItemDirectory)/SOD -f net6.0 -r linux-$(Architecture) $(PerformanceDirectory)/src/tools/ScenarioMeasurement/SizeOnDisk/SizeOnDisk.csproj
displayName: Build SizeOnDisk tool (Linux)
env:
- PERFLAB_TARGET_FRAMEWORKS: netcoreapp3.1
+ PERFLAB_TARGET_FRAMEWORKS: net6.0
condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))
# run perf testing in helix
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index 73432c9c408b1a..a57c1ab59fd589 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -36,6 +36,7 @@ jobs:
- ${{ if eq(parameters.platform, 'Linux_arm64') }}:
- ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}:
- (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673
+ - (Ubuntu.2104.Arm64.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.04-helix-arm64v8-20210922170819-34a2d72
- ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}:
- (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673
@@ -58,7 +59,7 @@ jobs:
- RedHat.7.Amd64.Open
- SLES.15.Amd64.Open
- (Fedora.34.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix-20210913123654-4f64125
- - (Ubuntu.1910.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-19.10-helix-amd64-cfcfd50-20191030180623
+ - (Ubuntu.2104.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.04-helix-amd64-20210922170909-34a2d72
- (Debian.10.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-bfcd90a-20200121150006
- ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}:
- ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}:
@@ -69,10 +70,11 @@ jobs:
- SLES.12.Amd64.Open
- SLES.15.Amd64.Open
- (Fedora.34.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-34-helix-20210913123654-4f64125
- - (Ubuntu.1910.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-19.10-helix-amd64-cfcfd50-20191030180623
+ - (Ubuntu.2104.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-21.04-helix-amd64-20210922170909-34a2d72
- (Debian.10.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-20210304164434-56c6673
- (Debian.11.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64-20210304164428-5a7c380
- (Mariner.1.0.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-1.0-helix-20210528192219-92bf620
+ - (openSUSE.15.2.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64-20211018152525-9cc02fe
- ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}:
- (Centos.7.Amd64.Open)Ubuntu.1604.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-mlnet-helix-20210714125435-dde38af
- RedHat.7.Amd64.Open
diff --git a/eng/pipelines/runtime-manual.yml b/eng/pipelines/runtime-manual.yml
index 83f9e891dab573..3be3efb85c9e2c 100644
--- a/eng/pipelines/runtime-manual.yml
+++ b/eng/pipelines/runtime-manual.yml
@@ -58,6 +58,34 @@ jobs:
interpreter: true
testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+#
+# MacCatalyst interp - requires AOT Compilation and Interp flags
+# Build the whole product using Mono and run libraries tests
+# The test app is built with the App Sandbox entitlement
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ runtimeFlavor: mono
+ platforms:
+ - MacCatalyst_x64
+ # don't run tests on arm64 PRs until we can get significantly more devices
+ - ${{ if eq(variables['isFullMatrix'], true) }}:
+ - MacCatalyst_arm64
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: AllSubsets_Mono_AppSandbox
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=adhoc /p:RunAOTCompilation=true /p:MonoForceInterpreter=true /p:BuildDarwinFrameworks=true /p:EnableAppSandbox=true
+ timeoutInMinutes: 180
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ interpreter: true
+ testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+
#
# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size
# Build the whole product using Mono and run libraries tests
@@ -332,47 +360,46 @@ jobs:
eq(variables['isManualOrIsNotPR'], true),
eq(variables['isFullMatrix'], true))
-# Disabled due to https://github.com/dotnet/runtime/issues/61721
-#- template: /eng/pipelines/common/platform-matrix.yml
- #parameters:
- #jobTemplate: /eng/pipelines/common/global-build-job.yml
- #helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
- #buildConfig: release
- #runtimeFlavor: mono
- #platforms:
- #- Browser_wasm_win
- #variables:
- ## map dependencies variables to local variables
- #- name: librariesContainsChange
- #value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- #- name: monoContainsChange
- #value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
- #jobParameters:
- #testGroup: innerloop
- #nameSuffix: Windows_wasm_AOT
- #buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg)
- #timeoutInMinutes: 180
- #condition: >-
- #or(
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
- #eq(variables['isManualOrIsNotPR'], true),
- #eq(variables['isFullMatrix'], true))
- ## extra steps, run tests
- #extraStepsTemplate: /eng/pipelines/libraries/helix.yml
- #extraStepsParameters:
- #creator: dotnet-bot
- #testRunNamePrefixSuffix: Mono_$(_BuildConfig)
- #extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg)
- #scenarios:
- #- normal
- #condition: >-
- #or(
- #eq(variables['librariesContainsChange'], true),
- #eq(variables['monoContainsChange'], true),
- #eq(variables['isManualOrIsNotPR'], true),
- #eq(variables['isFullMatrix'], true))
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: release
+ runtimeFlavor: mono
+ platforms:
+ - Browser_wasm_win
+ variables:
+ # map dependencies variables to local variables
+ - name: librariesContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
+ - name: monoContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: Windows_wasm_AOT
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg)
+ timeoutInMinutes: 180
+ condition: >-
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
+ eq(variables['isManualOrIsNotPR'], true),
+ eq(variables['isFullMatrix'], true))
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg)
+ scenarios:
+ - normal
+ condition: >-
+ or(
+ eq(variables['librariesContainsChange'], true),
+ eq(variables['monoContainsChange'], true),
+ eq(variables['isManualOrIsNotPR'], true),
+ eq(variables['isFullMatrix'], true))
#
# Build for Browser/wasm, with EnableAggressiveTrimming=true
diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml
index a38deea1927a5c..eb39d2e2c53a90 100644
--- a/eng/pipelines/runtime-staging.yml
+++ b/eng/pipelines/runtime-staging.yml
@@ -154,6 +154,51 @@ jobs:
eq(variables['isManualOrIsNotPR'], true),
eq(variables['isFullMatrix'], true))
+#
+# MacCatalyst interp - requires AOT Compilation and Interp flags
+# Build the whole product using Mono and run libraries tests
+# The test app is built with the App Sandbox entitlement
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ runtimeFlavor: mono
+ platforms:
+ - MacCatalyst_x64
+ # don't run tests on arm64 PRs until we can get significantly more devices
+ - ${{ if eq(variables['isFullMatrix'], true) }}:
+ - MacCatalyst_arm64
+ variables:
+ # map dependencies variables to local variables
+ - name: librariesContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
+ - name: monoContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: AllSubsets_Mono_AppSandbox
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=adhoc /p:RunAOTCompilation=true /p:MonoForceInterpreter=true /p:BuildDarwinFrameworks=true /p:EnableAppSandbox=true
+ timeoutInMinutes: 180
+ condition: >-
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ interpreter: true
+ testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ condition: >-
+ or(
+ eq(variables['librariesContainsChange'], true),
+ eq(variables['monoContainsChange'], true),
+ eq(variables['isFullMatrix'], true))
+
#
# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size
# Build the whole product using Mono and run libraries tests
@@ -493,47 +538,44 @@ jobs:
# Build Browser_wasm, on windows, and run tests with AOT
#
# Disabled due to https://github.com/dotnet/runtime/issues/61721
-#- template: /eng/pipelines/common/platform-matrix.yml
- #parameters:
- #jobTemplate: /eng/pipelines/common/global-build-job.yml
- #helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
- #buildConfig: release
- #runtimeFlavor: mono
- #platforms:
- #- Browser_wasm_win
- #variables:
- ## map dependencies variables to local variables
- #- name: librariesContainsChange
- #value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- #- name: monoContainsChange
- #value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
- #jobParameters:
- #testGroup: innerloop
- #nameSuffix: Windows_wasm_AOT
- #buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg)
- #timeoutInMinutes: 180
- #condition: >-
- #or(
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
- #eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
- #eq(variables['isManualOrIsNotPR'], true),
- #eq(variables['isFullMatrix'], true))
- ## extra steps, run tests
- #extraStepsTemplate: /eng/pipelines/libraries/helix.yml
- #extraStepsParameters:
- #creator: dotnet-bot
- #testRunNamePrefixSuffix: Mono_$(_BuildConfig)
- #extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg)
- #scenarios:
- #- normal
- #condition: >-
- #or(
- #eq(variables['librariesContainsChange'], true),
- #eq(variables['monoContainsChange'], true),
- #eq(variables['isManualOrIsNotPR'], true),
- #eq(variables['isFullMatrix'], true))
-
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: release
+ runtimeFlavor: mono
+ platforms:
+ - Browser_wasm_win
+ variables:
+ # map dependencies variables to local variables
+ - name: librariesContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
+ - name: monoContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: Windows_wasm_AOT
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:BrowserHost=windows /p:EnableAggressiveTrimming=true /p:BuildAOTTestsOnHelix=true /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg)
+ timeoutInMinutes: 180
+ condition: >-
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ extraHelixArguments: /p:BrowserHost=windows /p:NeedsToBuildWasmAppsOnHelix=true $(_runSmokeTestsOnlyArg)
+ scenarios:
+ - normal
+ condition: >-
+ or(
+ eq(variables['librariesContainsChange'], true),
+ eq(variables['monoContainsChange'], true),
+ eq(variables['isFullMatrix'], true))
#
# Build Browser_wasm, on windows, and run Wasm.Build.Tests
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index af8b9c116dd80c..04fca6cc817093 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -1026,7 +1026,8 @@ jobs:
runtimeFlavor: mono
platforms:
- OSX_x64
- - Linux_arm64
+ - ${{ if eq(variables['isFullMatrix'], true) }}:
+ - Linux_arm64
helixQueueGroup: pr
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
jobParameters:
@@ -1035,7 +1036,10 @@ jobs:
liveRuntimeBuildConfig: release
runtimeVariant: minijit
condition: >-
- eq(variables['isFullMatrix'], true)
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
#
# Mono CoreCLR runtime Test executions using live libraries in interpreter mode
@@ -1047,7 +1051,8 @@ jobs:
runtimeFlavor: mono
platforms:
- OSX_x64
- - Linux_arm64
+ - ${{ if eq(variables['isFullMatrix'], true) }}:
+ - Linux_arm64
helixQueueGroup: pr
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
jobParameters:
@@ -1056,7 +1061,10 @@ jobs:
liveRuntimeBuildConfig: release
runtimeVariant: monointerpreter
condition: >-
- eq(variables['isFullMatrix'], true)
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
#
# Mono CoreCLR runtime Test executions using live libraries and LLVM AOT
# Only when Mono is changed
@@ -1078,7 +1086,10 @@ jobs:
liveRuntimeBuildConfig: release
runtimeVariant: llvmaot
condition: >-
- eq(variables['isFullMatrix'], true)
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
#
# Mono CoreCLR runtime Test executions using live libraries and LLVM Full AOT
@@ -1101,7 +1112,10 @@ jobs:
liveRuntimeBuildConfig: release
runtimeVariant: llvmfullaot
condition: >-
- eq(variables['isFullMatrix'], true)
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_runtimetests.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
#
# Libraries Release Test Execution against a release mono runtime.
diff --git a/eng/testing/performance/android_scenarios.proj b/eng/testing/performance/android_scenarios.proj
index 338a696150fb3d..52af8fa1678dc8 100644
--- a/eng/testing/performance/android_scenarios.proj
+++ b/eng/testing/performance/android_scenarios.proj
@@ -1,4 +1,9 @@
+
+ true
+ 1.0.0-prerelease.21566.2
+ %HELIX_CORRELATION_PAYLOAD%\microsoft.dotnet.xharness.cli\$(MicrosoftDotNetXHarnessCLIVersion)\tools\net6.0\any\Microsoft.DotNet.XHarness.CLI.dll
+
python3
$(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk
@@ -42,5 +47,11 @@
$(Python) test.py sod --scenario-name "%(Identity)"
$(Python) post.py
+
+ $(WorkItemDirectory)
+ echo on;set XHARNESSPATH=$(XharnessPath);cd $(ScenarioDirectory)helloandroid;copy %HELIX_CORRELATION_PAYLOAD%\HelloAndroidWithDiag.apk .;$(Python) pre.py
+ $(Python) test.py devicestartup --device-type android --package-path pub\HelloAndroidWithDiag.apk --package-name net.dot.HelloAndroid --exit-code 42 --scenario-name "%(Identity)"
+ $(Python) post.py
+
-
\ No newline at end of file
+
diff --git a/eng/testing/performance/performance-setup.ps1 b/eng/testing/performance/performance-setup.ps1
index 5e2837f802ad7e..d85325ee1349d5 100644
--- a/eng/testing/performance/performance-setup.ps1
+++ b/eng/testing/performance/performance-setup.ps1
@@ -148,7 +148,13 @@ if ($AndroidMono) {
{
mkdir $WorkItemDirectory
}
- Copy-Item -path "$SourceDirectory\artifacts\bin\AndroidSampleApp\arm64\Release\android-arm64\publish\apk\bin\HelloAndroid.apk" $PayloadDirectory
+ if(Test-Path "$SourceDirectory\androidHelloWorld\HelloAndroid.apk") {
+ Copy-Item -path "$SourceDirectory\androidHelloWorld\HelloAndroid.apk" $PayloadDirectory -Verbose
+ }
+
+ if(Test-Path "$SourceDirectory\androidHelloWorldWithDiag\HelloAndroidWithDiag.apk") {
+ Copy-Item -path "$SourceDirectory\androidHelloWorldWithDiag\HelloAndroidWithDiag.apk" $PayloadDirectory -Verbose
+ }
Copy-Item -path "$SourceDirectory\MauiAndroidDefault.apk" $PayloadDirectory
$SetupArguments = $SetupArguments -replace $Architecture, 'arm64'
}
diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets
index 17783b7ed5ec43..192363c4b170a1 100644
--- a/eng/testing/tests.mobile.targets
+++ b/eng/testing/tests.mobile.targets
@@ -6,7 +6,7 @@
$(AppBundleRoot)runonly\$(AssemblyName)
$([MSBuild]::NormalizeDirectory('$(PublishDir)', 'AppBundle'))
$([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))
-
+
true
BundleTestAndroidApp
Publish
@@ -36,7 +36,6 @@
- $(Configuration)
$(AdditionalXHarnessArguments) --expected-exit-code $(ExpectedExitCode)
@@ -55,9 +54,9 @@
-
-
@@ -184,7 +183,7 @@
-
+
<_ShellCommandSeparator Condition="'$(OS)' == 'Windows_NT'">&&
<_ShellCommandSeparator Condition="'$(OS)' != 'Windows_NT'">&&
+ false
@@ -28,7 +29,7 @@
<_XHarnessArgs Condition="'$(OS)' != 'Windows_NT'">wasm $XHARNESS_COMMAND --app=. --output-directory=$XHARNESS_OUT
<_XHarnessArgs Condition="'$(OS)' == 'Windows_NT'">wasm %XHARNESS_COMMAND% --app=. --output-directory=%XHARNESS_OUT%
- <_XHarnessArgs Condition="'$(Scenario)' != 'WasmTestOnBrowser' and '$(Scenario)' != 'BuildWasmApps'">$(_XHarnessArgs) --engine=$(JSEngine) $(JSEngineArgs) --js-file=main.js
+ <_XHarnessArgs Condition="'$(Scenario)' != 'WasmTestOnBrowser' and '$(Scenario)' != 'BuildWasmApps'">$(_XHarnessArgs) --engine=$(JSEngine) $(JSEngineArgs) --js-file=test-main.js
<_XHarnessArgs Condition="'$(BrowserHost)' == 'windows'">$(_XHarnessArgs) --browser=chrome --browser-path=%HELIX_CORRELATION_PAYLOAD%\chrome-win\chrome.exe
<_XHarnessArgs Condition="'$(IsFunctionalTest)' == 'true'" >$(_XHarnessArgs) --expected-exit-code=$(ExpectedExitCode)
<_XHarnessArgs Condition="'$(WasmXHarnessArgs)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgs)
diff --git a/global.json b/global.json
index ae4b4d3af4b13a..d70a6fc7b84469 100644
--- a/global.json
+++ b/global.json
@@ -12,10 +12,10 @@
"python3": "3.7.1"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.21602.3",
- "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21602.3",
- "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.21602.3",
- "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.21602.3",
+ "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.21609.2",
+ "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21609.2",
+ "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.21609.2",
+ "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.21609.2",
"Microsoft.Build.NoTargets": "3.1.0",
"Microsoft.Build.Traversal": "3.0.23",
"Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21576.4"
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/AssemblyExtensions.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/AssemblyExtensions.cs
index e5c1db9ce14dbd..332dd6301cde09 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/AssemblyExtensions.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Metadata/AssemblyExtensions.cs
@@ -12,13 +12,21 @@ public static partial class AssemblyExtensions
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe partial bool InternalTryGetRawMetadata(QCallAssembly assembly, ref byte* blob, ref int length);
- // Retrieves the metadata section of the assembly, for use with System.Reflection.Metadata.MetadataReader.
- // - Returns false upon failure. Metadata might not be available for some assemblies, such as AssemblyBuilder, .NET
- // native images, etc.
- // - Callers should not write to the metadata blob
- // - The metadata blob pointer will remain valid as long as the AssemblyLoadContext with which the assembly is
- // associated, is alive. The caller is responsible for keeping the assembly object alive while accessing the
- // metadata blob.
+ ///
+ /// Retrieves the metadata section of the assembly, for use with .
+ ///
+ /// The assembly from which to retrieve the metadata.
+ /// When this method returns, contains the pointer to the metadata section blob.
+ /// When this method returns, contains the length of the metadata section blob.
+ ///
+ /// if the metadata is retrieved successfully; upon failure.
+ /// The metadata might not be available for some assemblies, such as , AOT images, etc.
+ ///
+ ///
+ /// Callers should not write to the metadata blob.
+ /// The metadata blob pointer will remain valid as long as the assembly is alive.
+ /// The caller is responsible for keeping the assembly object alive while accessing the metadata blob.
+ ///
[CLSCompliant(false)] // out byte* blob
public static unsafe bool TryGetRawMetadata(this Assembly assembly, out byte* blob, out int length)
{
diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
index 41a85755b01d0f..41735099fb2e79 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
@@ -1181,7 +1181,7 @@ internal static class StubHelpers
internal static extern IntPtr GetNDirectTarget(IntPtr pMD);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr GetDelegateTarget(Delegate pThis, ref IntPtr pStubArg);
+ internal static extern IntPtr GetDelegateTarget(Delegate pThis);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void ClearLastError();
@@ -1348,11 +1348,6 @@ internal static void CheckStringLength(uint length)
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr GetStubContext();
-#if TARGET_64BIT
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr GetStubContextAddr();
-#endif // TARGET_64BIT
-
#if FEATURE_ARRAYSTUB_AS_IL
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void ArrayTypeCheck(object o, object[] arr);
@@ -1363,6 +1358,7 @@ internal static void CheckStringLength(uint length)
internal static extern void MulticastDebuggerTraceHelper(object o, int count);
#endif
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern IntPtr NextCallReturnAddress();
} // class StubHelpers
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index fc62daa4406ef3..9ed65b7a5d1e06 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -4551,8 +4551,10 @@ void MethodContext::dmpGetFunctionFixedEntryPoint(DWORDLONG key, const Agnostic_
printf("GetFunctionFixedEntryPoint key ftn-%016llX, value %s", key,
SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value).c_str());
}
-void MethodContext::repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult)
+void MethodContext::repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult)
{
+ // The isUnsafeFunctionPointer has no impact on the resulting value.
+ // It helps produce side-effects in the runtime only.
DWORDLONG key = CastHandle(ftn);
AssertMapAndKeyExist(GetFunctionFixedEntryPoint, key, ": key %016llX", key);
Agnostic_CORINFO_CONST_LOOKUP value = GetFunctionFixedEntryPoint->Get(key);
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 6e7c910f16d586..2e695c6d221772 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -569,7 +569,7 @@ class MethodContext
void recGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult);
void dmpGetFunctionFixedEntryPoint(DWORDLONG key, const Agnostic_CORINFO_CONST_LOOKUP& value);
- void repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult);
+ void repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult);
void recGetFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num, CORINFO_FIELD_HANDLE result);
void dmpGetFieldInClass(DLD key, DWORDLONG value);
@@ -1067,7 +1067,7 @@ enum mcPackets
Packet_GetMethodNameFromMetadata = 161,
Packet_GetDefaultEqualityComparerClass = 162,
Packet_CompareTypesForCast = 163,
- Packet_CompareTypesForEquality = 164,
+ Packet_CompareTypesForEquality = 164,
Packet_GetUnboxedEntry = 165,
Packet_GetClassNameFromMetadata = 166,
Packet_GetTypeInstantiationArgument = 167,
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index ef1afc408afff3..50fed27bb63bc2 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -1439,10 +1439,13 @@ void interceptor_ICJI::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, /* I
// return a directly callable address. This can be used similarly to the
// value returned by getFunctionEntryPoint() except that it is
// guaranteed to be multi callable entrypoint.
-void interceptor_ICJI::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult)
+void interceptor_ICJI::getFunctionFixedEntryPoint(
+ CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
+ CORINFO_CONST_LOOKUP* pResult)
{
mc->cr->AddCall("getFunctionFixedEntryPoint");
- original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, pResult);
+ original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult);
mc->recGetFunctionFixedEntryPoint(ftn, pResult);
}
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 60ba9a998d5544..0b0507ddb121d9 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -985,10 +985,11 @@ void interceptor_ICJI::getFunctionEntryPoint(
void interceptor_ICJI::getFunctionFixedEntryPoint(
CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP* pResult)
{
mcs->AddCall("getFunctionFixedEntryPoint");
- original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, pResult);
+ original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult);
}
void* interceptor_ICJI::getMethodSync(
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index 0c01d60937d6ab..6e1d86a176271c 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -862,9 +862,10 @@ void interceptor_ICJI::getFunctionEntryPoint(
void interceptor_ICJI::getFunctionFixedEntryPoint(
CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP* pResult)
{
- original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, pResult);
+ original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult);
}
void* interceptor_ICJI::getMethodSync(
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp
index ab34fb4623da37..350931cf3aaf9c 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp
@@ -1272,10 +1272,13 @@ void MyICJI::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, /* IN */
// return a directly callable address. This can be used similarly to the
// value returned by getFunctionEntryPoint() except that it is
// guaranteed to be multi callable entrypoint.
-void MyICJI::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult)
+void MyICJI::getFunctionFixedEntryPoint(
+ CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
+ CORINFO_CONST_LOOKUP* pResult)
{
jitInstance->mc->cr->AddCall("getFunctionFixedEntryPoint");
- jitInstance->mc->repGetFunctionFixedEntryPoint(ftn, pResult);
+ jitInstance->mc->repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult);
}
// get the synchronization handle that is passed to monXstatic function
diff --git a/src/coreclr/build-runtime.cmd b/src/coreclr/build-runtime.cmd
index dc17395f486319..d14d06111dabae 100644
--- a/src/coreclr/build-runtime.cmd
+++ b/src/coreclr/build-runtime.cmd
@@ -324,6 +324,9 @@ if NOT DEFINED PYTHON (
set __CMakeTarget=
for /f "delims=" %%a in ("-%__RequestedBuildComponents%-") do (
set "string=%%a"
+ if not "!string:-hosts-=!"=="!string!" (
+ set __CMakeTarget=!__CMakeTarget! hosts
+ )
if not "!string:-jit-=!"=="!string!" (
set __CMakeTarget=!__CMakeTarget! jit
)
@@ -739,7 +742,7 @@ echo -all: Builds all configurations and platforms.
echo Build architecture: one of -x64, -x86, -arm, -arm64 ^(default: -x64^).
echo Build type: one of -Debug, -Checked, -Release ^(default: -Debug^).
echo -component ^ : specify this option one or more times to limit components built to those specified.
-echo Allowed ^: jit alljits runtime paltests iltools
+echo Allowed ^: hosts jit alljits runtime paltests iltools
echo -enforcepgo: verify after the build that PGO was used for key DLLs, and fail the build if not
echo -pgoinstrument: generate instrumented code for profile guided optimization enabled binaries.
echo -cmakeargs: user-settable additional arguments passed to CMake.
diff --git a/src/coreclr/build-runtime.sh b/src/coreclr/build-runtime.sh
index 7adfb63f21743d..cbf18f67b2dd0d 100755
--- a/src/coreclr/build-runtime.sh
+++ b/src/coreclr/build-runtime.sh
@@ -22,7 +22,7 @@ usage_list+=("-pgodatapath: path to profile guided optimization data.")
usage_list+=("-pgoinstrument: generate instrumented code for profile guided optimization enabled binaries.")
usage_list+=("-skipcrossarchnative: Skip building cross-architecture native binaries.")
usage_list+=("-staticanalyzer: use scan_build static analyzer.")
-usage_list+=("-component: Build individual components instead of the full project. Available options are 'jit', 'runtime', 'paltests', 'alljits', and 'iltools'. Can be specified multiple times.")
+usage_list+=("-component: Build individual components instead of the full project. Available options are 'hosts', 'jit', 'runtime', 'paltests', 'alljits', and 'iltools'. Can be specified multiple times.")
setup_dirs_local()
{
diff --git a/src/coreclr/components.cmake b/src/coreclr/components.cmake
index 01d3db0c87d210..81ec07a3f42d59 100644
--- a/src/coreclr/components.cmake
+++ b/src/coreclr/components.cmake
@@ -1,6 +1,7 @@
# Define all the individually buildable components of the CoreCLR build and their respective targets
add_component(jit)
add_component(alljits)
+add_component(hosts)
add_component(runtime)
add_component(paltests paltests_install)
add_component(iltools)
@@ -16,5 +17,7 @@ add_dependencies(runtime coreclr_misc)
# The runtime build requires the clrjit and iltools builds
add_dependencies(runtime jit iltools)
+add_dependencies(runtime hosts)
+
# The cross-components build is separate, so we don't need to add a dependency on coreclr_misc
add_component(crosscomponents)
diff --git a/src/coreclr/debug/dbgutil/machoreader.cpp b/src/coreclr/debug/dbgutil/machoreader.cpp
index 48fea72682f205..d2801547cb9ba9 100644
--- a/src/coreclr/debug/dbgutil/machoreader.cpp
+++ b/src/coreclr/debug/dbgutil/machoreader.cpp
@@ -126,19 +126,41 @@ MachOModule::TryLookupSymbol(const char* symbolName, uint64_t* symbolValue)
_ASSERTE(m_nlists != nullptr);
_ASSERTE(m_strtabAddress != 0);
- for (int i = 0; i < m_dysymtabCommand->nextdefsym; i++)
+ // First, search just the "external" export symbols
+ if (TryLookupSymbol(m_dysymtabCommand->iextdefsym, m_dysymtabCommand->nextdefsym, symbolName, symbolValue))
{
- std::string name = GetSymbolName(i);
- // Skip the leading underscores to match Linux externs
- if (name[0] == '_')
- {
- name.erase(0, 1);
- }
- if (strcmp(name.c_str(), symbolName) == 0)
- {
- *symbolValue = m_loadBias + m_nlists[i].n_value;
- return true;
- }
+ m_reader.Trace("SYM: Found '%s' in external symbols\n", symbolName);
+ return true;
+ }
+ m_reader.Trace("SYM: Missed '%s' in external symbols\n", symbolName);
+
+ // If not found in external symbols, search all of them
+ if (TryLookupSymbol(0, m_symtabCommand->nsyms, symbolName, symbolValue))
+ {
+ m_reader.Trace("SYM: Found '%s' in all symbols\n", symbolName);
+ return true;
+ }
+ m_reader.Trace("SYM: Missed '%s' in all symbols\n", symbolName);
+ }
+ *symbolValue = 0;
+ return false;
+}
+
+bool
+MachOModule::TryLookupSymbol(int start, int nsyms, const char* symbolName, uint64_t* symbolValue)
+{
+ for (int i = 0; i < nsyms; i++)
+ {
+ std::string name = GetSymbolName(start + i);
+
+ // Skip the leading underscores to match Linux externs
+ const char* currentName = name.length() > 0 && name[0] == '_' ? name.c_str() + 1 : name.c_str();
+
+ // Does this symbol match?
+ if (strcmp(currentName, symbolName) == 0)
+ {
+ *symbolValue = m_loadBias + m_nlists[start + i].n_value;
+ return true;
}
}
*symbolValue = 0;
@@ -263,26 +285,30 @@ MachOModule::ReadSymbolTable()
_ASSERTE(m_symtabCommand != nullptr);
_ASSERTE(m_strtabAddress == 0);
- m_reader.TraceVerbose("SYM: symoff %08x nsyms %d stroff %08x strsize %d iext %d next %d\n",
+ m_reader.TraceVerbose("SYM: symoff %08x nsyms %d stroff %08x strsize %d iext %d next %d iundef %d nundef %d extref %d nextref %d\n",
m_symtabCommand->symoff,
m_symtabCommand->nsyms,
m_symtabCommand->stroff,
m_symtabCommand->strsize,
m_dysymtabCommand->iextdefsym,
- m_dysymtabCommand->nextdefsym);
-
- // Read the external symbol part of symbol table. An array of "nlist" structs.
- void* extSymbolTableAddress = (void*)(GetAddressFromFileOffset(m_symtabCommand->symoff) + (m_dysymtabCommand->iextdefsym * sizeof(nlist_64)));
- size_t symtabSize = sizeof(nlist_64) * m_dysymtabCommand->nextdefsym;
+ m_dysymtabCommand->nextdefsym,
+ m_dysymtabCommand->iundefsym,
+ m_dysymtabCommand->nundefsym,
+ m_dysymtabCommand->extrefsymoff,
+ m_dysymtabCommand->nextrefsyms);
+
+ // Read the entire symbol part of symbol table. An array of "nlist" structs.
+ void* symbolTableAddress = (void*)GetAddressFromFileOffset(m_symtabCommand->symoff);
+ size_t symtabSize = sizeof(nlist_64) * m_symtabCommand->nsyms;
m_nlists = (nlist_64*)malloc(symtabSize);
if (m_nlists == nullptr)
{
- m_reader.Trace("ERROR: Failed to allocate %zu byte external symbol table\n", symtabSize);
+ m_reader.Trace("ERROR: Failed to allocate %zu byte symtab\n", symtabSize);
return false;
}
- if (!m_reader.ReadMemory(extSymbolTableAddress, m_nlists, symtabSize))
+ if (!m_reader.ReadMemory(symbolTableAddress, m_nlists, symtabSize))
{
- m_reader.Trace("ERROR: Failed to read external symtab at %p of %zu\n", extSymbolTableAddress, symtabSize);
+ m_reader.Trace("ERROR: Failed to read symtab at %p of %zu\n", symbolTableAddress, symtabSize);
return false;
}
diff --git a/src/coreclr/debug/dbgutil/machoreader.h b/src/coreclr/debug/dbgutil/machoreader.h
index bb9ffe0fdd7ceb..a5f458b17ff2d5 100644
--- a/src/coreclr/debug/dbgutil/machoreader.h
+++ b/src/coreclr/debug/dbgutil/machoreader.h
@@ -37,6 +37,7 @@ class MachOModule
bool ReadHeader();
bool TryLookupSymbol(const char* symbolName, uint64_t* symbolValue);
+ bool TryLookupSymbol(int start, int nsyms, const char* symbolName, uint64_t* symbolValue);
bool EnumerateSegments();
private:
diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src
index 4fc0af3d682340..2a529b2f4a779d 100644
--- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src
+++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src
@@ -23,6 +23,7 @@ nativeStringResourceTable_mscorrc
#PAL_CatchHardwareExceptionHolderEnter
#PAL_CatchHardwareExceptionHolderExit
#PAL_bsearch
+#PAL_CopyModuleData
#PAL_errno
#PAL_fflush
#PAL__flushall
@@ -142,6 +143,7 @@ nativeStringResourceTable_mscorrc
#LocalAlloc
#LocalFree
#MapViewOfFile
+#MapViewOfFileEx
#MoveFileExW
#MultiByteToWideChar
#OpenProcess
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index 939830dc32ddc3..ace66eac266709 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -2532,13 +2532,15 @@ uint8_t** gc_heap::background_mark_stack_array = 0;
size_t gc_heap::background_mark_stack_array_length = 0;
+BOOL gc_heap::processed_eph_overflow_p = FALSE;
+
+#ifdef USE_REGIONS
+BOOL gc_heap::background_overflow_p = FALSE;
+#else //USE_REGIONS
uint8_t* gc_heap::background_min_overflow_address =0;
uint8_t* gc_heap::background_max_overflow_address =0;
-BOOL gc_heap::processed_eph_overflow_p = FALSE;
-
-#ifndef USE_REGIONS
uint8_t* gc_heap::background_min_soh_overflow_address =0;
uint8_t* gc_heap::background_max_soh_overflow_address =0;
@@ -2548,7 +2550,7 @@ heap_segment* gc_heap::saved_overflow_ephemeral_seg = 0;
heap_segment* gc_heap::saved_sweep_ephemeral_seg = 0;
uint8_t* gc_heap::saved_sweep_ephemeral_start = 0;
-#endif //!USE_REGIONS
+#endif //USE_REGIONS
Thread* gc_heap::bgc_thread = 0;
@@ -23429,6 +23431,21 @@ void gc_heap::mark_object (uint8_t* o THREAD_NUMBER_DCL)
#ifdef BACKGROUND_GC
+#ifdef USE_REGIONS
+void gc_heap::set_background_overflow_p (uint8_t* oo)
+{
+ heap_segment* overflow_region = get_region_info_for_address (oo);
+ overflow_region->flags |= heap_segment_flags_overflow;
+ dprintf (3,("setting overflow flag for region %p", heap_segment_mem (overflow_region)));
+#ifdef MULTIPLE_HEAPS
+ gc_heap* overflow_heap = heap_segment_heap (overflow_region);
+#else
+ gc_heap* overflow_heap = nullptr;
+#endif
+ overflow_heap->background_overflow_p = TRUE;
+}
+#endif //USE_REGIONS
+
void gc_heap::background_mark_simple1 (uint8_t* oo THREAD_NUMBER_DCL)
{
uint8_t** mark_stack_limit = &background_mark_stack_array[background_mark_stack_array_length];
@@ -23495,9 +23512,13 @@ void gc_heap::background_mark_simple1 (uint8_t* oo THREAD_NUMBER_DCL)
}
else
{
- dprintf (3,("mark stack overflow for object %Ix ", (size_t)oo));
+ dprintf (3,("background mark stack overflow for object %Ix ", (size_t)oo));
+#ifdef USE_REGIONS
+ set_background_overflow_p (oo);
+#else //USE_REGIONS
background_min_overflow_address = min (background_min_overflow_address, oo);
background_max_overflow_address = max (background_max_overflow_address, oo);
+#endif //USE_REGIONS
}
}
else
@@ -23609,9 +23630,13 @@ void gc_heap::background_mark_simple1 (uint8_t* oo THREAD_NUMBER_DCL)
}
else
{
- dprintf (3,("mark stack overflow for object %Ix ", (size_t)oo));
+ dprintf (3,("background mark stack overflow for object %Ix ", (size_t)oo));
+#ifdef USE_REGIONS
+ set_background_overflow_p (oo);
+#else //USE_REGIONS
background_min_overflow_address = min (background_min_overflow_address, oo);
background_max_overflow_address = max (background_max_overflow_address, oo);
+#endif //USE_REGIONS
}
}
}
@@ -23887,13 +23912,13 @@ uint8_t* gc_heap::background_first_overflow (uint8_t* min_add,
BOOL concurrent_p,
BOOL small_object_p)
{
+#ifdef USE_REGIONS
+ return heap_segment_mem (seg);
+#else
uint8_t* o = 0;
if (small_object_p)
{
-#ifdef USE_REGIONS
- return find_first_object (min_add, heap_segment_mem (seg));
-#else
if (in_range_for_segment (min_add, seg))
{
// min_add was the beginning of gen1 when we did the concurrent
@@ -23919,11 +23944,11 @@ uint8_t* gc_heap::background_first_overflow (uint8_t* min_add,
}
}
}
-#endif //USE_REGIONS
}
o = max (heap_segment_mem (seg), min_add);
return o;
+#endif //USE_REGIONS
}
void gc_heap::background_process_mark_overflow_internal (uint8_t* min_add, uint8_t* max_add,
@@ -23948,7 +23973,9 @@ void gc_heap::background_process_mark_overflow_internal (uint8_t* min_add, uint8
exclusive_sync* loh_alloc_lock = 0;
+#ifndef USE_REGIONS
dprintf (2,("Processing Mark overflow [%Ix %Ix]", (size_t)min_add, (size_t)max_add));
+#endif
#ifdef MULTIPLE_HEAPS
// We don't have each heap scan all heaps concurrently because we are worried about
// multiple threads calling things like find_first_object.
@@ -23981,9 +24008,14 @@ void gc_heap::background_process_mark_overflow_internal (uint8_t* min_add, uint8
#ifdef USE_REGIONS
if (heap_segment_overflow_p (seg))
{
- assert (!concurrent_p);
- current_min_add = max (heap_segment_mem (seg), min_add);
- current_max_add = min (heap_segment_allocated (seg), max_add);
+ seg->flags &= ~heap_segment_flags_overflow;
+ current_min_add = heap_segment_mem (seg);
+ current_max_add = heap_segment_allocated (seg);
+ dprintf (2,("Processing Mark overflow [%Ix %Ix]", (size_t)current_min_add, (size_t)current_max_add));
+ }
+ else
+ {
+ current_min_add = current_max_add = 0;
}
#endif //USE_REGIONS
uint8_t* o = hp->background_first_overflow (current_min_add, seg, concurrent_p, small_object_segments);
@@ -24034,15 +24066,19 @@ void gc_heap::background_process_mark_overflow_internal (uint8_t* min_add, uint8
}
}
- dprintf (2, ("went through overflow objects in segment %Ix (%d) (so far %Id marked)",
- heap_segment_mem (seg), (small_object_segments ? 0 : 1), total_marked_objects));
-
+#ifdef USE_REGIONS
+ if (current_max_add != 0)
+#endif //USE_REGIONS
+ {
+ dprintf (2, ("went through overflow objects in segment %Ix (%d) (so far %Id marked)",
+ heap_segment_mem (seg), (small_object_segments ? 0 : 1), total_marked_objects));
+ }
#ifndef USE_REGIONS
if (concurrent_p && (seg == hp->saved_overflow_ephemeral_seg))
{
break;
}
-#endif //USE_REGIONS
+#endif //!USE_REGIONS
seg = heap_segment_next_in_range (seg);
}
@@ -24071,36 +24107,18 @@ BOOL gc_heap::background_process_mark_overflow (BOOL concurrent_p)
if (concurrent_p)
{
assert (!processed_eph_overflow_p);
-
+#ifndef USE_REGIONS
if ((background_max_overflow_address != 0) &&
(background_min_overflow_address != MAX_PTR))
{
-#ifdef USE_REGIONS
- // We don't want to step into the ephemeral regions so remember these regions and
- // be sure to process them later. An FGC cannot happen while we are going through
- // the region lists.
- for (int i = 0; i < max_generation; i++)
- {
- heap_segment* region = generation_start_segment (generation_of (i));
- while (region)
- {
- if ((heap_segment_mem (region) <= background_max_overflow_address) &&
- (heap_segment_allocated (region) >= background_min_overflow_address))
- {
- region->flags |= heap_segment_flags_overflow;
- }
- region = heap_segment_next (region);
- }
- }
-#else //USE_REGIONS
// We have overflow to process but we know we can't process the ephemeral generations
// now (we actually could process till the current gen1 start but since we are going to
// make overflow per segment, for now I'll just stop at the saved gen1 start.
saved_overflow_ephemeral_seg = ephemeral_heap_segment;
background_max_soh_overflow_address = heap_segment_reserved (saved_overflow_ephemeral_seg);
background_min_soh_overflow_address = generation_allocation_start (generation_of (max_generation - 1));
-#endif //USE_REGIONS
}
+#endif //!USE_REGIONS
}
else
{
@@ -24114,12 +24132,18 @@ BOOL gc_heap::background_process_mark_overflow (BOOL concurrent_p)
{
// if there was no more overflow we just need to process what we didn't process
// on the saved ephemeral segment.
+#ifdef USE_REGIONS
+ if (!background_overflow_p)
+#else
if ((background_max_overflow_address == 0) && (background_min_overflow_address == MAX_PTR))
+#endif //USE_REGIONS
{
dprintf (2, ("final processing mark overflow - no more overflow since last time"));
grow_mark_array_p = FALSE;
}
-#ifndef USE_REGIONS
+#ifdef USE_REGIONS
+ background_overflow_p = TRUE;
+#else
background_min_overflow_address = min (background_min_overflow_address,
background_min_soh_overflow_address);
background_max_overflow_address = max (background_max_overflow_address,
@@ -24131,8 +24155,12 @@ BOOL gc_heap::background_process_mark_overflow (BOOL concurrent_p)
BOOL overflow_p = FALSE;
recheck:
+#ifdef USE_REGIONS
+ if (background_overflow_p)
+#else
if ((! ((background_max_overflow_address == 0)) ||
! ((background_min_overflow_address == MAX_PTR))))
+#endif
{
overflow_p = TRUE;
@@ -24155,11 +24183,17 @@ BOOL gc_heap::background_process_mark_overflow (BOOL concurrent_p)
grow_mark_array_p = TRUE;
}
+#ifdef USE_REGIONS
+ uint8_t* min_add = 0;
+ uint8_t* max_add = 0;
+ background_overflow_p = FALSE;
+#else
uint8_t* min_add = background_min_overflow_address;
uint8_t* max_add = background_max_overflow_address;
background_max_overflow_address = 0;
background_min_overflow_address = MAX_PTR;
+#endif
background_process_mark_overflow_internal (min_add, max_add, concurrent_p);
if (!concurrent_p)
@@ -32375,6 +32409,7 @@ void gc_heap::background_scan_dependent_handles (ScanContext *sc)
if (!s_fScanRequired)
{
+#ifndef USE_REGIONS
uint8_t* all_heaps_max = 0;
uint8_t* all_heaps_min = MAX_PTR;
int i;
@@ -32390,6 +32425,7 @@ void gc_heap::background_scan_dependent_handles (ScanContext *sc)
g_heaps[i]->background_max_overflow_address = all_heaps_max;
g_heaps[i]->background_min_overflow_address = all_heaps_min;
}
+#endif //!USE_REGIONS
}
dprintf(2, ("Starting all gc thread mark stack overflow processing"));
@@ -32920,12 +32956,14 @@ void gc_heap::background_mark_phase ()
bpromoted_bytes (heap_number) = 0;
static uint32_t num_sizedrefs = 0;
+#ifdef USE_REGIONS
+ background_overflow_p = FALSE;
+#else
background_min_overflow_address = MAX_PTR;
background_max_overflow_address = 0;
-#ifndef USE_REGIONS
background_min_soh_overflow_address = MAX_PTR;
background_max_soh_overflow_address = 0;
-#endif //!USE_REGIONS
+#endif //USE_REGIONS
processed_eph_overflow_p = FALSE;
//set up the mark lists from g_mark_list
@@ -33125,7 +33163,7 @@ void gc_heap::background_mark_phase ()
enable_preemptive ();
-#ifdef MULTIPLE_HEAPS
+#if defined(MULTIPLE_HEAPS) && !defined(USE_REGIONS)
bgc_t_join.join(this, gc_join_concurrent_overflow);
if (bgc_t_join.joined())
{
@@ -33142,6 +33180,7 @@ void gc_heap::background_mark_phase ()
all_heaps_max = g_heaps[i]->background_max_overflow_address;
if (all_heaps_min > g_heaps[i]->background_min_overflow_address)
all_heaps_min = g_heaps[i]->background_min_overflow_address;
+
}
for (i = 0; i < n_heaps; i++)
{
@@ -33151,7 +33190,7 @@ void gc_heap::background_mark_phase ()
dprintf(3, ("Starting all bgc threads after updating the overflow info"));
bgc_t_join.restart();
}
-#endif //MULTIPLE_HEAPS
+#endif //MULTIPLE_HEAPS && !USE_REGIONS
disable_preemptive (true);
diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h
index 136db1ae8c1b95..081b9a539c073c 100644
--- a/src/coreclr/gc/gcpriv.h
+++ b/src/coreclr/gc/gcpriv.h
@@ -2466,6 +2466,10 @@ class gc_heap
void verify_mark_bits_cleared (uint8_t* obj, size_t s);
PER_HEAP
void clear_all_mark_array();
+#ifdef USE_REGIONS
+ PER_HEAP
+ void set_background_overflow_p (uint8_t* oo);
+#endif
#ifdef BGC_SERVO_TUNING
@@ -4282,18 +4286,21 @@ class gc_heap
PER_HEAP
size_t background_mark_stack_array_length;
+ // We can't process the ephemeral range concurrently so we
+ // wait till final mark to process it.
PER_HEAP
- uint8_t* background_min_overflow_address;
+ BOOL processed_eph_overflow_p;
+#ifdef USE_REGIONS
PER_HEAP
- uint8_t* background_max_overflow_address;
+ BOOL background_overflow_p;
+#else
+ PER_HEAP
+ uint8_t* background_min_overflow_address;
- // We can't process the ephemeral range concurrently so we
- // wait till final mark to process it.
PER_HEAP
- BOOL processed_eph_overflow_p;
+ uint8_t* background_max_overflow_address;
-#ifndef USE_REGIONS
PER_HEAP
uint8_t* background_min_soh_overflow_address;
diff --git a/src/coreclr/hosts/corerun/CMakeLists.txt b/src/coreclr/hosts/corerun/CMakeLists.txt
index ef20f57e0bb8d8..b95f4c87bd878a 100644
--- a/src/coreclr/hosts/corerun/CMakeLists.txt
+++ b/src/coreclr/hosts/corerun/CMakeLists.txt
@@ -32,4 +32,4 @@ else(CLR_CMAKE_HOST_WIN32)
endif()
endif(CLR_CMAKE_HOST_WIN32)
-install_clr(TARGETS corerun DESTINATIONS . COMPONENT runtime)
+install_clr(TARGETS corerun DESTINATIONS . COMPONENT hosts)
diff --git a/src/coreclr/hosts/coreshim/CMakeLists.txt b/src/coreclr/hosts/coreshim/CMakeLists.txt
index 5c6a2fd28899d8..e25caf7dfa5d44 100644
--- a/src/coreclr/hosts/coreshim/CMakeLists.txt
+++ b/src/coreclr/hosts/coreshim/CMakeLists.txt
@@ -22,4 +22,4 @@ target_link_libraries(CoreShim
${STATIC_MT_VCRT_LIB}
)
-install_clr(TARGETS CoreShim DESTINATIONS . COMPONENT runtime)
+install_clr(TARGETS CoreShim DESTINATIONS . COMPONENT hosts)
diff --git a/src/coreclr/inc/cor.h b/src/coreclr/inc/cor.h
index ee82e433695ebe..8ccc151cc0378e 100644
--- a/src/coreclr/inc/cor.h
+++ b/src/coreclr/inc/cor.h
@@ -1942,7 +1942,7 @@ inline ULONG CorSigUncompressData( // return number of bytes of that compre
ULONG dwSizeOfData = 0;
// We don't know how big the signature is, so we'll just say that it's big enough
- if (FAILED(CorSigUncompressData(pData, 0xff, pDataOut, &dwSizeOfData)))
+ if (FAILED(CorSigUncompressData(pData, 0xff, reinterpret_cast(pDataOut), reinterpret_cast(&dwSizeOfData))))
{
*pDataOut = 0;
return (ULONG)-1;
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 4cc0c44b83c1df..ae24d18c2c9667 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -885,11 +885,6 @@ enum CorInfoIntrinsics
CORINFO_INTRINSIC_Array_Get, // Get the value of an element in an array
CORINFO_INTRINSIC_Array_Address, // Get the address of an element in an array
CORINFO_INTRINSIC_Array_Set, // Set the value of an element in an array
- CORINFO_INTRINSIC_RTH_GetValueInternal,
- CORINFO_INTRINSIC_Object_GetType,
- CORINFO_INTRINSIC_StubHelpers_GetStubContext,
- CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr,
- CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress,
CORINFO_INTRINSIC_ByReference_Ctor,
CORINFO_INTRINSIC_ByReference_Value,
@@ -2929,6 +2924,7 @@ class ICorDynamicInfo : public ICorStaticInfo
// guaranteed to be multi callable entrypoint.
virtual void getFunctionFixedEntryPoint(
CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP * pResult) = 0;
// get the synchronization handle that is passed to monXstatic function
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index da724e75da6073..d912b90b8612b1 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -502,6 +502,7 @@ void getFunctionEntryPoint(
void getFunctionFixedEntryPoint(
CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP* pResult) override;
void* getMethodSync(
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index b51f56b2df5c78..21679993f73a60 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 = { /* 0c6f2d8d-f1b7-4c28-bbe8-36c8f6b35fbf */
- 0xc6f2d8d,
- 0xf1b7,
- 0x4c28,
- { 0xbb, 0xe8, 0x36, 0xc8, 0xf6, 0xb3, 0x5f, 0xbf}
+constexpr GUID JITEEVersionIdentifier = { /* 3d9496d4-03f7-4eb0-bf7a-a88794e74537 */
+ 0x3d9496d4,
+ 0x03f7,
+ 0x4eb0,
+ {0xbf, 0x7a, 0xa8, 0x87, 0x94, 0xe7, 0x45, 0x37}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/inc/stresslog.h b/src/coreclr/inc/stresslog.h
index 508bc91edb72a0..4ee3acaeb8bb6c 100644
--- a/src/coreclr/inc/stresslog.h
+++ b/src/coreclr/inc/stresslog.h
@@ -45,6 +45,8 @@
#ifndef _ASSERTE
#define _ASSERTE(expr)
#endif
+#else
+#include // offsetof
#endif // STRESS_LOG_ANALYZER
/* The STRESS_LOG* macros work like printf. In fact the use printf in their implementation
@@ -322,11 +324,39 @@ class StressLog {
static const size_t MAX_MODULES = 5;
ModuleDesc modules[MAX_MODULES]; // descriptor of the modules images
-#if defined(HOST_WINDOWS) && defined(HOST_64BIT)
+#if defined(HOST_64BIT)
#define MEMORY_MAPPED_STRESSLOG
+#ifdef HOST_WINDOWS
+#define MEMORY_MAPPED_STRESSLOG_BASE_ADDRESS (void*)0x400000000000
+#else
+#define MEMORY_MAPPED_STRESSLOG_BASE_ADDRESS nullptr
+#endif
+#endif
+
+#ifdef STRESS_LOG_ANALYZER
+ static size_t writing_base_address;
+ static size_t reading_base_address;
+
+ template
+ static T* TranslateMemoryMappedPointer(T* input)
+ {
+ if (input == nullptr)
+ {
+ return nullptr;
+ }
+
+ return ((T*)(((uint8_t*)input) - writing_base_address + reading_base_address));
+ }
+#else
+ template
+ static T* TranslateMemoryMappedPointer(T* input)
+ {
+ return input;
+ }
#endif
#ifdef MEMORY_MAPPED_STRESSLOG
+
MapViewHolder hMapView;
static void* AllocMemoryMapped(size_t n);
@@ -547,8 +577,14 @@ struct StressLogChunk
DWORD dwSig2;
#if !defined(STRESS_LOG_READONLY)
+
+#ifdef MEMORY_MAPPED_STRESSLOG
+ static bool s_memoryMapped;
+#endif //MEMORY_MAPPED_STRESSLOG
+
#ifdef HOST_WINDOWS
static HANDLE s_LogChunkHeap;
+#endif //HOST_WINDOWS
void * operator new (size_t size) throw()
{
@@ -556,43 +592,32 @@ struct StressLogChunk
{
return NULL;
}
-
- if (s_LogChunkHeap != NULL)
- {
- //no need to zero memory because we could handle garbage contents
- return HeapAlloc(s_LogChunkHeap, 0, size);
- }
- else
- {
#ifdef MEMORY_MAPPED_STRESSLOG
+ if (s_memoryMapped)
return StressLog::AllocMemoryMapped(size);
-#else
- return nullptr;
#endif //MEMORY_MAPPED_STRESSLOG
- }
- }
-
- void operator delete (void * chunk)
- {
- if (s_LogChunkHeap != NULL)
- HeapFree (s_LogChunkHeap, 0, chunk);
- }
+#ifdef HOST_WINDOWS
+ _ASSERTE(s_LogChunkHeap);
+ return HeapAlloc(s_LogChunkHeap, 0, size);
#else
- void* operator new (size_t size) throw()
- {
- if (IsInCantAllocStressLogRegion())
- {
- return NULL;
- }
-
return malloc(size);
+#endif //HOST_WINDOWS
}
- void operator delete (void* chunk)
+ void operator delete (void * chunk)
{
+#ifdef MEMORY_MAPPED_STRESSLOG
+ if (s_memoryMapped)
+ return;
+#endif //MEMORY_MAPPED_STRESSLOG
+#ifdef HOST_WINDOWS
+ _ASSERTE(s_LogChunkHeap);
+ HeapFree (s_LogChunkHeap, 0, chunk);
+#else
free(chunk);
+#endif //HOST_WINDOWS
}
-#endif
+
#endif //!STRESS_LOG_READONLY
StressLogChunk (StressLogChunk * p = NULL, StressLogChunk * n = NULL)
@@ -772,7 +797,7 @@ class ThreadStressLog {
BOOL IsValid () const
{
- return chunkListHead != NULL && (!curWriteChunk || curWriteChunk->IsValid ());
+ return chunkListHead != NULL && (!curWriteChunk || StressLog::TranslateMemoryMappedPointer(curWriteChunk)->IsValid ());
}
#ifdef STRESS_LOG_READONLY
diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
index 9f51c43b765ee0..031d2ba75b505f 100644
--- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
@@ -1205,10 +1205,11 @@ void WrapICorJitInfo::getFunctionEntryPoint(
void WrapICorJitInfo::getFunctionFixedEntryPoint(
CORINFO_METHOD_HANDLE ftn,
+ bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP* pResult)
{
API_ENTER(getFunctionFixedEntryPoint);
- wrapHnd->getFunctionFixedEntryPoint(ftn, pResult);
+ wrapHnd->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult);
API_LEAVE(getFunctionFixedEntryPoint);
}
diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h
index 87eb4923ff743a..78c76a805ab3cd 100644
--- a/src/coreclr/jit/block.h
+++ b/src/coreclr/jit/block.h
@@ -1562,6 +1562,10 @@ class BasicBlockSimpleList
// and must be non-null. E.g.,
// for (BasicBlock* const block : BasicBlockRangeList(startBlock, endBlock)) ...
//
+// Note that endBlock->bbNext is captured at the beginning of the iteration. Thus, any blocks
+// inserted before that will continue the iteration. In particular, inserting blocks between endBlock
+// and endBlock->bbNext will yield unexpected results, as the iteration will continue longer than desired.
+//
class BasicBlockRangeList
{
BasicBlock* m_begin;
diff --git a/src/coreclr/jit/clrjit.natvis b/src/coreclr/jit/clrjit.natvis
index 1a62108f08267a..aa5fb650c28de4 100644
--- a/src/coreclr/jit/clrjit.natvis
+++ b/src/coreclr/jit/clrjit.natvis
@@ -25,6 +25,12 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
BB{bbNum,d}; {bbJumpKind,en}
+
+ REMOVED
+ BB{lpTop->bbNum,d}-BB{lpBottom->bbNum,d} pre-h:BB{lpHead->bbNum,d} e:BB{lpEntry->bbNum,d} {lpFlags,en}
+ BB{lpTop->bbNum,d}-BB{lpBottom->bbNum,d} h:BB{lpHead->bbNum,d} e:BB{lpEntry->bbNum,d} {lpFlags,en}
+
+
type={ebdHandlerType}
diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp
index 785ae4f96647be..19a24869146225 100644
--- a/src/coreclr/jit/codegenarmarch.cpp
+++ b/src/coreclr/jit/codegenarmarch.cpp
@@ -3838,7 +3838,7 @@ void CodeGen::genPushCalleeSavedRegisters()
// The amount to subtract from SP before starting to store the callee-saved registers. It might be folded into the
// first save instruction as a "predecrement" amount, if possible.
- int calleeSaveSPDelta = 0;
+ int calleeSaveSpDelta = 0;
if (isFramePointerUsed())
{
@@ -3920,7 +3920,7 @@ void CodeGen::genPushCalleeSavedRegisters()
// separate SUB instruction or the SP adjustment might be folded in to the first STP if there is
// no outgoing argument space AND no local frame space, that is, if the only thing the frame does
// is save callee-saved registers (and possibly varargs argument registers).
- calleeSaveSPDelta = totalFrameSize;
+ calleeSaveSpDelta = totalFrameSize;
offset = (int)compiler->compLclFrameSize;
}
@@ -4015,7 +4015,7 @@ void CodeGen::genPushCalleeSavedRegisters()
// slots. In fact, we are not; any empty alignment slots were calculated in
// Compiler::lvaAssignFrameOffsets() and its callees.
- int calleeSaveSPDeltaUnaligned = totalFrameSize - compiler->compLclFrameSize;
+ int calleeSaveSpDeltaUnaligned = totalFrameSize - compiler->compLclFrameSize;
if (genSaveFpLrWithAllCalleeSavedRegisters)
{
JITDUMP("Frame type 5 (save FP/LR at top). #outsz=%d; #framesz=%d; LclFrameSize=%d\n",
@@ -4035,19 +4035,19 @@ void CodeGen::genPushCalleeSavedRegisters()
frameType = 3;
- calleeSaveSPDeltaUnaligned -= 2 * REGSIZE_BYTES; // 2 for FP, LR which we'll save later.
+ calleeSaveSpDeltaUnaligned -= 2 * REGSIZE_BYTES; // 2 for FP, LR which we'll save later.
// We'll take care of these later, but callee-saved regs code shouldn't see them.
maskSaveRegsInt &= ~(RBM_FP | RBM_LR);
}
- assert(calleeSaveSPDeltaUnaligned >= 0);
- assert((calleeSaveSPDeltaUnaligned % 8) == 0); // It better at least be 8 byte aligned.
- calleeSaveSPDelta = AlignUp((UINT)calleeSaveSPDeltaUnaligned, STACK_ALIGN);
+ assert(calleeSaveSpDeltaUnaligned >= 0);
+ assert((calleeSaveSpDeltaUnaligned % 8) == 0); // It better at least be 8 byte aligned.
+ calleeSaveSpDelta = AlignUp((UINT)calleeSaveSpDeltaUnaligned, STACK_ALIGN);
- offset = calleeSaveSPDelta - calleeSaveSPDeltaUnaligned;
+ offset = calleeSaveSpDelta - calleeSaveSpDeltaUnaligned;
- JITDUMP(" calleeSaveSPDelta=%d, offset=%d\n", calleeSaveSPDelta, offset);
+ JITDUMP(" calleeSaveSpDelta=%d, offset=%d\n", calleeSaveSpDelta, offset);
// At most one alignment slot between SP and where we store the callee-saved registers.
assert((offset == 0) || (offset == REGSIZE_BYTES));
@@ -4068,8 +4068,10 @@ void CodeGen::genPushCalleeSavedRegisters()
assert(frameType != 0);
- JITDUMP(" offset=%d, calleeSaveSPDelta=%d\n", offset, calleeSaveSPDelta);
- genSaveCalleeSavedRegistersHelp(maskSaveRegsInt | maskSaveRegsFloat, offset, -calleeSaveSPDelta);
+ const int calleeSaveSpOffset = offset;
+
+ JITDUMP(" offset=%d, calleeSaveSpDelta=%d\n", offset, calleeSaveSpDelta);
+ genSaveCalleeSavedRegistersHelp(maskSaveRegsInt | maskSaveRegsFloat, offset, -calleeSaveSpDelta);
offset += genCountBits(maskSaveRegsInt | maskSaveRegsFloat) * REGSIZE_BYTES;
@@ -4114,10 +4116,10 @@ void CodeGen::genPushCalleeSavedRegisters()
{
assert(!genSaveFpLrWithAllCalleeSavedRegisters);
- int remainingFrameSz = totalFrameSize - calleeSaveSPDelta;
+ int remainingFrameSz = totalFrameSize - calleeSaveSpDelta;
assert(remainingFrameSz > 0);
assert((remainingFrameSz % 16) == 0); // this is guaranteed to be 16-byte aligned because each component --
- // totalFrameSize and calleeSaveSPDelta -- is 16-byte aligned.
+ // totalFrameSize and calleeSaveSpDelta -- is 16-byte aligned.
if (compiler->lvaOutgoingArgSpaceSize > 504)
{
@@ -4166,14 +4168,14 @@ void CodeGen::genPushCalleeSavedRegisters()
else if (frameType == 4)
{
assert(genSaveFpLrWithAllCalleeSavedRegisters);
- offsetSpToSavedFp = calleeSaveSPDelta - (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) -
+ offsetSpToSavedFp = calleeSaveSpDelta - (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) -
2 * REGSIZE_BYTES; // -2 for FP, LR
}
else if (frameType == 5)
{
assert(genSaveFpLrWithAllCalleeSavedRegisters);
- offsetSpToSavedFp = calleeSaveSPDelta - (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) -
+ offsetSpToSavedFp = calleeSaveSpDelta - (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) -
2 * REGSIZE_BYTES; // -2 for FP, LR
JITDUMP(" offsetSpToSavedFp=%d\n", offsetSpToSavedFp);
genEstablishFramePointer(offsetSpToSavedFp, /* reportUnwindData */ true);
@@ -4181,10 +4183,10 @@ void CodeGen::genPushCalleeSavedRegisters()
// We just established the frame pointer chain; don't do it again.
establishFramePointer = false;
- int remainingFrameSz = totalFrameSize - calleeSaveSPDelta;
+ int remainingFrameSz = totalFrameSize - calleeSaveSpDelta;
assert(remainingFrameSz > 0);
assert((remainingFrameSz % 16) == 0); // this is guaranteed to be 16-byte aligned because each component --
- // totalFrameSize and calleeSaveSPDelta -- is 16-byte aligned.
+ // totalFrameSize and calleeSaveSpDelta -- is 16-byte aligned.
JITDUMP(" remainingFrameSz=%d\n", remainingFrameSz);
@@ -4204,6 +4206,13 @@ void CodeGen::genPushCalleeSavedRegisters()
}
assert(offset == totalFrameSize);
+
+ // Save off information about the frame for later use
+ //
+ compiler->compFrameInfo.frameType = frameType;
+ compiler->compFrameInfo.calleeSaveSpOffset = calleeSaveSpOffset;
+ compiler->compFrameInfo.calleeSaveSpDelta = calleeSaveSpDelta;
+ compiler->compFrameInfo.offsetSpToSavedFp = offsetSpToSavedFp;
#endif // TARGET_ARM64
}
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index ef0c34ec5a01d2..237a22c6782f0f 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -5194,22 +5194,22 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
regMaskTP regsToRestoreMask = rsRestoreRegs;
- int totalFrameSize = genTotalFrameSize();
+ const int totalFrameSize = genTotalFrameSize();
- int calleeSaveSPOffset = 0; // This will be the starting place for restoring the callee-saved registers, in
- // decreasing order.
- int frameType = 0; // An indicator of what type of frame we are popping.
- int calleeSaveSPDelta = 0; // Amount to add to SP after callee-saved registers have been restored.
+ // Fetch info about the frame we saved when creating the prolog.
+ //
+ const int frameType = compiler->compFrameInfo.frameType;
+ const int calleeSaveSpOffset = compiler->compFrameInfo.calleeSaveSpOffset;
+ const int calleeSaveSpDelta = compiler->compFrameInfo.calleeSaveSpDelta;
+ const int offsetSpToSavedFp = compiler->compFrameInfo.offsetSpToSavedFp;
- if (isFramePointerUsed())
+ switch (frameType)
{
- if ((compiler->lvaOutgoingArgSpaceSize == 0) && (totalFrameSize <= 504) &&
- !genSaveFpLrWithAllCalleeSavedRegisters)
+ case 1:
{
JITDUMP("Frame type 1. #outsz=0; #framesz=%d; localloc? %s\n", totalFrameSize,
dspBool(compiler->compLocallocUsed));
- frameType = 1;
if (compiler->compLocallocUsed)
{
// Restore sp from fp
@@ -5219,13 +5219,16 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
}
regsToRestoreMask &= ~(RBM_FP | RBM_LR); // We'll restore FP/LR at the end, and post-index SP.
-
- // Compute callee save SP offset which is at the top of local frame while the FP/LR is saved at the
- // bottom of stack.
- calleeSaveSPOffset = compiler->compLclFrameSize + 2 * REGSIZE_BYTES;
+ break;
}
- else if (totalFrameSize <= 512)
+
+ case 2:
{
+ JITDUMP("Frame type 2 (save FP/LR at bottom). #outsz=%d; #framesz=%d; localloc? %s\n",
+ unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, dspBool(compiler->compLocallocUsed));
+
+ assert(!genSaveFpLrWithAllCalleeSavedRegisters);
+
if (compiler->compLocallocUsed)
{
// Restore sp from fp
@@ -5235,52 +5238,22 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta);
}
- if (genSaveFpLrWithAllCalleeSavedRegisters)
- {
- JITDUMP("Frame type 4 (save FP/LR at top). #outsz=%d; #framesz=%d; localloc? %s\n",
- unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize,
- dspBool(compiler->compLocallocUsed));
-
- frameType = 4;
-
- calleeSaveSPOffset = compiler->compLclFrameSize;
-
- // Remove the frame after we're done restoring the callee-saved registers.
- calleeSaveSPDelta = totalFrameSize;
- }
- else
- {
- JITDUMP("Frame type 2 (save FP/LR at bottom). #outsz=%d; #framesz=%d; localloc? %s\n",
- unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize,
- dspBool(compiler->compLocallocUsed));
-
- frameType = 2;
-
- regsToRestoreMask &= ~(RBM_FP | RBM_LR); // We'll restore FP/LR at the end, and post-index SP.
-
- // Compute callee save SP offset which is at the top of local frame while the FP/LR is saved at the
- // bottom of stack.
- calleeSaveSPOffset = compiler->compLclFrameSize + 2 * REGSIZE_BYTES;
- }
+ regsToRestoreMask &= ~(RBM_FP | RBM_LR); // We'll restore FP/LR at the end, and post-index SP.
+ break;
}
- else if (!genSaveFpLrWithAllCalleeSavedRegisters)
+
+ case 3:
{
JITDUMP("Frame type 3 (save FP/LR at bottom). #outsz=%d; #framesz=%d; localloc? %s\n",
unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, dspBool(compiler->compLocallocUsed));
- frameType = 3;
+ assert(!genSaveFpLrWithAllCalleeSavedRegisters);
- int calleeSaveSPDeltaUnaligned = totalFrameSize - compiler->compLclFrameSize -
- 2 * REGSIZE_BYTES; // 2 for FP, LR which we'll restore later.
- assert(calleeSaveSPDeltaUnaligned >= 0);
- assert((calleeSaveSPDeltaUnaligned % 8) == 0); // It better at least be 8 byte aligned.
- calleeSaveSPDelta = AlignUp((UINT)calleeSaveSPDeltaUnaligned, STACK_ALIGN);
-
- JITDUMP(" calleeSaveSPDelta=%d\n", calleeSaveSPDelta);
+ JITDUMP(" calleeSaveSpDelta=%d\n", calleeSaveSpDelta);
regsToRestoreMask &= ~(RBM_FP | RBM_LR); // We'll restore FP/LR at the end, and (hopefully) post-index SP.
- int remainingFrameSz = totalFrameSize - calleeSaveSPDelta;
+ int remainingFrameSz = totalFrameSize - calleeSaveSpDelta;
assert(remainingFrameSz > 0);
if (compiler->lvaOutgoingArgSpaceSize > 504)
@@ -5332,83 +5305,91 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
// Unlike frameType=1 or frameType=2 that restore SP at the end,
// frameType=3 already adjusted SP above to delete local frame.
// There is at most one alignment slot between SP and where we store the callee-saved registers.
- calleeSaveSPOffset = calleeSaveSPDelta - calleeSaveSPDeltaUnaligned;
- assert((calleeSaveSPOffset == 0) || (calleeSaveSPOffset == REGSIZE_BYTES));
+ assert((calleeSaveSpOffset == 0) || (calleeSaveSpOffset == REGSIZE_BYTES));
+
+ break;
}
- else
+
+ case 4:
{
- JITDUMP("Frame type 5 (save FP/LR at top). #outsz=%d; #framesz=%d; localloc? %s\n",
+ JITDUMP("Frame type 4 (save FP/LR at top). #outsz=%d; #framesz=%d; localloc? %s\n",
unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, dspBool(compiler->compLocallocUsed));
- frameType = 5;
+ assert(genSaveFpLrWithAllCalleeSavedRegisters);
+
+ if (compiler->compLocallocUsed)
+ {
+ // Restore sp from fp
+ // sub sp, fp, #outsz // Uses #outsz if FP/LR stored at bottom
+ int SPtoFPdelta = genSPtoFPdelta();
+ GetEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, SPtoFPdelta);
+ compiler->unwindSetFrameReg(REG_FPBASE, SPtoFPdelta);
+ }
+ break;
+ }
- int calleeSaveSPDeltaUnaligned = totalFrameSize - compiler->compLclFrameSize;
- assert(calleeSaveSPDeltaUnaligned >= 0);
- assert((calleeSaveSPDeltaUnaligned % 8) == 0); // It better at least be 8 byte aligned.
- calleeSaveSPDelta = AlignUp((UINT)calleeSaveSPDeltaUnaligned, STACK_ALIGN);
+ case 5:
+ {
+ JITDUMP("Frame type 5 (save FP/LR at top). #outsz=%d; #framesz=%d; localloc? %s\n",
+ unsigned(compiler->lvaOutgoingArgSpaceSize), totalFrameSize, dspBool(compiler->compLocallocUsed));
- calleeSaveSPOffset = calleeSaveSPDelta - calleeSaveSPDeltaUnaligned;
- assert((calleeSaveSPOffset == 0) || (calleeSaveSPOffset == REGSIZE_BYTES));
+ assert((calleeSaveSpOffset == 0) || (calleeSaveSpOffset == REGSIZE_BYTES));
// Restore sp from fp:
// sub sp, fp, #sp-to-fp-delta
// This is the same whether there is localloc or not. Note that we don't need to do anything to remove the
// "remainingFrameSz" to reverse the SUB of that amount in the prolog.
-
- int offsetSpToSavedFp = calleeSaveSPDelta -
- (compiler->info.compIsVarArgs ? MAX_REG_ARG * REGSIZE_BYTES : 0) -
- 2 * REGSIZE_BYTES; // -2 for FP, LR
GetEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, offsetSpToSavedFp);
compiler->unwindSetFrameReg(REG_FPBASE, offsetSpToSavedFp);
+ break;
}
- }
- else
- {
- // No frame pointer (no chaining).
- NYI("Frame without frame pointer");
- calleeSaveSPOffset = 0;
+
+ default:
+ unreached();
}
- JITDUMP(" calleeSaveSPOffset=%d, calleeSaveSPDelta=%d\n", calleeSaveSPOffset, calleeSaveSPDelta);
- genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, calleeSaveSPOffset, calleeSaveSPDelta);
+ JITDUMP(" calleeSaveSpOffset=%d, calleeSaveSpDelta=%d\n", calleeSaveSpOffset, calleeSaveSpDelta);
+ genRestoreCalleeSavedRegistersHelp(regsToRestoreMask, calleeSaveSpOffset, calleeSaveSpDelta);
- if (frameType == 1)
+ switch (frameType)
{
- // Generate:
- // ldp fp,lr,[sp],#framesz
+ case 1:
+ {
+ // Generate:
+ // ldp fp,lr,[sp],#framesz
- GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, totalFrameSize,
- INS_OPTS_POST_INDEX);
- compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, -totalFrameSize);
- }
- else if (frameType == 2)
- {
- // Generate:
- // ldr fp,lr,[sp,#outsz]
- // add sp,sp,#framesz
+ GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE, totalFrameSize,
+ INS_OPTS_POST_INDEX);
+ compiler->unwindSaveRegPairPreindexed(REG_FP, REG_LR, -totalFrameSize);
+ break;
+ }
- GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE,
- compiler->lvaOutgoingArgSpaceSize);
- compiler->unwindSaveRegPair(REG_FP, REG_LR, compiler->lvaOutgoingArgSpaceSize);
+ case 2:
+ {
+ // Generate:
+ // ldr fp,lr,[sp,#outsz]
+ // add sp,sp,#framesz
- GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, totalFrameSize);
- compiler->unwindAllocStack(totalFrameSize);
- }
- else if (frameType == 3)
- {
- // Nothing to do after restoring callee-saved registers.
- }
- else if (frameType == 4)
- {
- // Nothing to do after restoring callee-saved registers.
- }
- else if (frameType == 5)
- {
- // Nothing to do after restoring callee-saved registers.
- }
- else
- {
- unreached();
+ GetEmitter()->emitIns_R_R_R_I(INS_ldp, EA_PTRSIZE, REG_FP, REG_LR, REG_SPBASE,
+ compiler->lvaOutgoingArgSpaceSize);
+ compiler->unwindSaveRegPair(REG_FP, REG_LR, compiler->lvaOutgoingArgSpaceSize);
+
+ GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, totalFrameSize);
+ compiler->unwindAllocStack(totalFrameSize);
+ break;
+ }
+ case 3:
+ case 4:
+ case 5:
+ {
+ // Nothing to do after restoring callee-saved registers.
+ break;
+ }
+
+ default:
+ {
+ unreached();
+ }
}
}
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index e56c96b026c0b1..fcb6f12e3d7fe1 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5245,26 +5245,42 @@ void Compiler::placeLoopAlignInstructions()
JITDUMP("Inside placeLoopAlignInstructions for %d loops.\n", loopAlignCandidates);
// Add align only if there were any loops that needed alignment
- weight_t minBlockSoFar = BB_MAX_WEIGHT;
- BasicBlock* bbHavingAlign = nullptr;
+ weight_t minBlockSoFar = BB_MAX_WEIGHT;
+ BasicBlock* bbHavingAlign = nullptr;
+ BasicBlock::loopNumber currentAlignedLoopNum = BasicBlock::NOT_IN_LOOP;
+
+ if ((fgFirstBB != nullptr) && fgFirstBB->isLoopAlign())
+ {
+ // Adding align instruction in prolog is not supported
+ // hence just remove that loop from our list.
+ loopsToProcess--;
+ }
+
for (BasicBlock* const block : Blocks())
{
- if ((block == fgFirstBB) && block->isLoopAlign())
+ if (currentAlignedLoopNum != BasicBlock::NOT_IN_LOOP)
{
- // Adding align instruction in prolog is not supported
- // hence skip the align block if it is the first block.
- loopsToProcess--;
- continue;
+ // We've been processing blocks within an aligned loop. Are we out of that loop now?
+ if (currentAlignedLoopNum != block->bbNatLoopNum)
+ {
+ currentAlignedLoopNum = BasicBlock::NOT_IN_LOOP;
+ }
}
- // If there is a unconditional jump
- if (opts.compJitHideAlignBehindJmp && (block->bbJumpKind == BBJ_ALWAYS))
+ // If there is a unconditional jump (which is not part of callf/always pair)
+ if (opts.compJitHideAlignBehindJmp && (block->bbJumpKind == BBJ_ALWAYS) && !block->isBBCallAlwaysPairTail())
{
+ // Track the lower weight blocks
if (block->bbWeight < minBlockSoFar)
{
- minBlockSoFar = block->bbWeight;
- bbHavingAlign = block;
- JITDUMP(FMT_BB ", bbWeight=" FMT_WT " ends with unconditional 'jmp' \n", block->bbNum, block->bbWeight);
+ if (currentAlignedLoopNum == BasicBlock::NOT_IN_LOOP)
+ {
+ // Ok to insert align instruction in this block because it is not part of any aligned loop.
+ minBlockSoFar = block->bbWeight;
+ bbHavingAlign = block;
+ JITDUMP(FMT_BB ", bbWeight=" FMT_WT " ends with unconditional 'jmp' \n", block->bbNum,
+ block->bbWeight);
+ }
}
}
@@ -5285,8 +5301,9 @@ void Compiler::placeLoopAlignInstructions()
}
bbHavingAlign->bbFlags |= BBF_HAS_ALIGN;
- minBlockSoFar = BB_MAX_WEIGHT;
- bbHavingAlign = nullptr;
+ minBlockSoFar = BB_MAX_WEIGHT;
+ bbHavingAlign = nullptr;
+ currentAlignedLoopNum = block->bbNext->bbNatLoopNum;
if (--loopsToProcess == 0)
{
@@ -5567,6 +5584,10 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
assert(info.compPatchpointInfo != nullptr);
}
+#if defined(TARGET_ARM64)
+ compFrameInfo = {0};
+#endif
+
virtualStubParamInfo = new (this, CMK_Unknown) VirtualStubParamInfo(IsTargetAbi(CORINFO_CORERT_ABI));
// compMatchedVM is set to true if both CPU/ABI and OS are matching the execution engine requirements
@@ -8828,29 +8849,32 @@ void cLiveness(Compiler* comp)
void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars)
{
static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
- printf("===================================================================== dCVarSet %u\n", sequenceNumber++);
+ printf("===================================================================== *CVarSet %u\n", sequenceNumber++);
dumpConvertedVarSet(comp, vars);
printf("\n"); // dumpConvertedVarSet() doesn't emit a trailing newline
}
-void cLoop(Compiler* comp, Compiler::LoopDsc* loop)
+void cLoop(Compiler* comp, unsigned loopNum)
{
static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
- printf("===================================================================== Loop %u\n", sequenceNumber++);
- printf("HEAD " FMT_BB "\n", loop->lpHead->bbNum);
- printf("TOP " FMT_BB "\n", loop->lpTop->bbNum);
- printf("ENTRY " FMT_BB "\n", loop->lpEntry->bbNum);
- if (loop->lpExitCnt == 1)
- {
- printf("EXIT " FMT_BB "\n", loop->lpExit->bbNum);
- }
- else
- {
- printf("EXITS %u\n", loop->lpExitCnt);
- }
- printf("BOTTOM " FMT_BB "\n", loop->lpBottom->bbNum);
+ printf("===================================================================== *Loop %u\n", sequenceNumber++);
+ comp->optPrintLoopInfo(loopNum, /* verbose */ true);
+ printf("\n");
+}
- comp->fgDispBasicBlocks(loop->lpHead, loop->lpBottom, true);
+void cLoopPtr(Compiler* comp, const Compiler::LoopDsc* loop)
+{
+ static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
+ printf("===================================================================== *LoopPtr %u\n", sequenceNumber++);
+ comp->optPrintLoopInfo(loop, /* verbose */ true);
+ printf("\n");
+}
+
+void cLoops(Compiler* comp)
+{
+ static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
+ printf("===================================================================== *Loops %u\n", sequenceNumber++);
+ comp->optPrintLoopTable();
}
void dBlock(BasicBlock* block)
@@ -8948,9 +8972,19 @@ void dCVarSet(VARSET_VALARG_TP vars)
cCVarSet(JitTls::GetCompiler(), vars);
}
-void dLoop(Compiler::LoopDsc* loop)
+void dLoop(unsigned loopNum)
{
- cLoop(JitTls::GetCompiler(), loop);
+ cLoop(JitTls::GetCompiler(), loopNum);
+}
+
+void dLoopPtr(const Compiler::LoopDsc* loop)
+{
+ cLoopPtr(JitTls::GetCompiler(), loop);
+}
+
+void dLoops()
+{
+ cLoops(JitTls::GetCompiler());
}
void dRegMask(regMaskTP mask)
@@ -9383,6 +9417,11 @@ void cTreeFlags(Compiler* comp, GenTree* tree)
chars += printf("[ICON_BBC_PTR]");
break;
+ case GTF_ICON_STATIC_BOX_PTR:
+
+ chars += printf("[GTF_ICON_STATIC_BOX_PTR]");
+ break;
+
case GTF_ICON_FIELD_OFF:
chars += printf("[ICON_FIELD_OFF]");
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 1a8d4040d5ecf4..17878f92806bf3 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -3466,7 +3466,7 @@ class Compiler
GenTree* gtReverseCond(GenTree* tree);
- bool gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly);
+ static bool gtHasRef(GenTree* tree, ssize_t lclNum);
bool gtHasLocalsWithAddrOp(GenTree* tree);
@@ -4411,6 +4411,7 @@ class Compiler
CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
CORINFO_THIS_TRANSFORM constraintCallThisTransform,
CorInfoIntrinsics* pIntrinsicID,
+ NamedIntrinsic* pIntrinsicName,
bool* isSpecialIntrinsic = nullptr);
GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
@@ -6645,7 +6646,7 @@ class Compiler
};
// 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 temporary recording their
+ // 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.
void optHoistLoopNest(unsigned lnum, LoopHoistContext* hoistCtxt);
@@ -6655,7 +6656,7 @@ class Compiler
//
void optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt);
- // Hoist all expressions in "blk" that are invariant in loop "lnum" (an index into the optLoopTable)
+ // 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".
void optHoistLoopBlocks(unsigned loopNum, ArrayStack* blocks, LoopHoistContext* hoistContext);
@@ -6679,6 +6680,13 @@ class Compiler
// written to, and SZ-array element type equivalence classes updated.
void optComputeLoopSideEffects();
+#ifdef DEBUG
+ bool optAnyChildNotRemoved(unsigned loopNum);
+#endif // DEBUG
+
+ // Mark a loop as removed.
+ void optMarkLoopRemoved(unsigned loopNum);
+
private:
// Requires "lnum" to be the index of an outermost loop in the loop table. Traverses the body of that loop,
// including all nested loops, and records the set of "side effects" of the loop: fields (object instance and
@@ -6765,6 +6773,8 @@ class Compiler
VARSET_TP lpVarInOut; // The set of variables that are IN or OUT during the execution of this loop
VARSET_TP lpVarUseDef; // The set of variables that are USE or DEF during the execution of this loop
+ // The following counts are used for hoisting profitability checks.
+
int lpHoistedExprCount; // The register count for the non-FP expressions from inside this loop that have been
// hoisted
int lpLoopVarCount; // The register count for the non-FP LclVars that are read/written inside this loop
@@ -6811,7 +6821,7 @@ class Compiler
// : Valid if LPFLG_VAR_INIT
};
- // The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var"
+ // The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var")
GenTree* lpTestTree; // pointer to the node containing the loop test
genTreeOps lpTestOper() const; // the type of the comparison between the iterator and the limit (GT_LE, GT_GE,
@@ -6839,44 +6849,46 @@ class Compiler
{
return lpTop->bbNum <= blk->bbNum && blk->bbNum <= lpBottom->bbNum;
}
- // Returns "true" iff "*this" (properly) contains the range [first, bottom] (allowing firsts
+
+ // Returns "true" iff "*this" (properly) contains the range [top, bottom] (allowing tops
// to be equal, but requiring bottoms to be different.)
- bool lpContains(BasicBlock* first, BasicBlock* bottom) const
+ bool lpContains(BasicBlock* top, BasicBlock* bottom) const
{
- return lpTop->bbNum <= first->bbNum && bottom->bbNum < lpBottom->bbNum;
+ return lpTop->bbNum <= top->bbNum && bottom->bbNum < lpBottom->bbNum;
}
- // Returns "true" iff "*this" (properly) contains "lp2" (allowing firsts to be equal, but requiring
+ // Returns "true" iff "*this" (properly) contains "lp2" (allowing tops to be equal, but requiring
// bottoms to be different.)
bool lpContains(const LoopDsc& lp2) const
{
return lpContains(lp2.lpTop, lp2.lpBottom);
}
- // Returns "true" iff "*this" is (properly) contained by the range [first, bottom]
- // (allowing firsts to be equal, but requiring bottoms to be different.)
- bool lpContainedBy(BasicBlock* first, BasicBlock* bottom) const
+ // Returns "true" iff "*this" is (properly) contained by the range [top, bottom]
+ // (allowing tops to be equal, but requiring bottoms to be different.)
+ bool lpContainedBy(BasicBlock* top, BasicBlock* bottom) const
{
- return first->bbNum <= lpTop->bbNum && lpBottom->bbNum < bottom->bbNum;
+ return top->bbNum <= lpTop->bbNum && lpBottom->bbNum < bottom->bbNum;
}
// Returns "true" iff "*this" is (properly) contained by "lp2"
- // (allowing firsts to be equal, but requiring bottoms to be different.)
+ // (allowing tops to be equal, but requiring bottoms to be different.)
bool lpContainedBy(const LoopDsc& lp2) const
{
- return lpContains(lp2.lpTop, lp2.lpBottom);
+ return lpContainedBy(lp2.lpTop, lp2.lpBottom);
}
// Returns "true" iff "*this" is disjoint from the range [top, bottom].
- bool lpDisjoint(BasicBlock* first, BasicBlock* bottom) const
+ bool lpDisjoint(BasicBlock* top, BasicBlock* bottom) const
{
- return bottom->bbNum < lpTop->bbNum || lpBottom->bbNum < first->bbNum;
+ return bottom->bbNum < lpTop->bbNum || lpBottom->bbNum < top->bbNum;
}
// Returns "true" iff "*this" is disjoint from "lp2".
bool lpDisjoint(const LoopDsc& lp2) const
{
return lpDisjoint(lp2.lpTop, lp2.lpBottom);
}
+
// Returns "true" iff the loop is well-formed (see code for defn).
bool lpWellFormed() const
{
@@ -6917,6 +6929,12 @@ class Compiler
BasicBlock* exit,
unsigned char exitCnt);
+#ifdef DEBUG
+ void optPrintLoopInfo(unsigned lnum, bool printVerbose = false);
+ void optPrintLoopInfo(const LoopDsc* loop, bool printVerbose = false);
+ void optPrintLoopTable();
+#endif
+
protected:
unsigned optCallCount; // number of calls made in the method
unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method
@@ -6924,17 +6942,6 @@ class Compiler
unsigned optLoopsCloned; // number of loops cloned in the current method.
#ifdef DEBUG
- void optPrintLoopInfo(unsigned loopNum,
- BasicBlock* lpHead,
- BasicBlock* lpTop,
- BasicBlock* lpEntry,
- BasicBlock* lpBottom,
- unsigned char lpExitCnt,
- BasicBlock* lpExit,
- unsigned parentLoop = BasicBlock::NOT_IN_LOOP) const;
- void optPrintLoopInfo(unsigned lnum) const;
- void optPrintLoopRecording(unsigned lnum) const;
-
void optCheckPreds();
#endif
@@ -6969,10 +6976,11 @@ class Compiler
// unshared with any other loop. Returns "true" iff the flowgraph has been modified
bool optCanonicalizeLoop(unsigned char loopInd);
- // 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".
- bool optLoopContains(unsigned l1, unsigned l2);
+ // 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;
// Updates the loop table by changing loop "loopInd", whose head is required
// to be "from", to be "to". Also performs this transformation for any
@@ -10330,6 +10338,24 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
unsigned compMapILvarNum(unsigned ILvarNum); // map accounting for hidden args
unsigned compMap2ILvarNum(unsigned varNum) const; // map accounting for hidden args
+#if defined(TARGET_ARM64)
+ struct FrameInfo
+ {
+ // Frame type (1-5)
+ int frameType;
+
+ // Distance from established (method body) SP to base of callee save area
+ int calleeSaveSpOffset;
+
+ // Amount to subtract from SP before saving (prolog) OR
+ // to add to SP after restoring (epilog) callee saves
+ int calleeSaveSpDelta;
+
+ // Distance from established SP to where caller's FP was saved
+ int offsetSpToSavedFp;
+ } compFrameInfo;
+#endif
+
//-------------------------------------------------------------------------
static void compStartup(); // One-time initialization
@@ -11426,11 +11452,6 @@ class GenTreeVisitor
GenTree** op1Use = &dynBlock->gtOp1;
GenTree** op2Use = &dynBlock->gtDynamicSize;
- if (TVisitor::UseExecutionOrder && dynBlock->gtEvalSizeFirst)
- {
- std::swap(op1Use, op2Use);
- }
-
result = WalkTree(op1Use, dynBlock);
if (result == fgWalkResult::WALK_ABORT)
{
@@ -11458,11 +11479,6 @@ class GenTreeVisitor
{
std::swap(op1Use, op2Use);
}
- if (dynBlock->gtEvalSizeFirst)
- {
- std::swap(op3Use, op2Use);
- std::swap(op2Use, op1Use);
- }
}
result = WalkTree(op1Use, dynBlock);
diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp
index f20baa57a74ef1..e763e2390930f8 100644
--- a/src/coreclr/jit/fgbasic.cpp
+++ b/src/coreclr/jit/fgbasic.cpp
@@ -894,12 +894,10 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
const bool isForceInline = (info.compFlags & CORINFO_FLG_FORCEINLINE) != 0;
const bool makeInlineObservations = (compInlineResult != nullptr);
const bool isInlining = compIsForInlining();
- const bool isPreJit = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT);
- const bool isTier1 = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1);
unsigned retBlocks = 0;
int prefixFlags = 0;
bool preciseScan = makeInlineObservations && compInlineResult->GetPolicy()->RequiresPreciseScan();
- const bool resolveTokens = preciseScan && (isPreJit || isTier1);
+ const bool resolveTokens = preciseScan;
// Track offsets where IL instructions begin in DEBUG builds. Used to
// validate debug info generated by the JIT.
@@ -4703,7 +4701,7 @@ void Compiler::fgRemoveBlock(BasicBlock* block, bool unreachable)
{
loopAlignCandidates++;
succBlock->bbFlags |= BBF_LOOP_ALIGN;
- JITDUMP("Propagating LOOP_ALIGN flag from " FMT_BB " to " FMT_BB " for loop# %d.", block->bbNum,
+ JITDUMP("Propagating LOOP_ALIGN flag from " FMT_BB " to " FMT_BB " for loop# %d.\n", block->bbNum,
succBlock->bbNum, block->bbNatLoopNum);
}
diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp
index 8fa10e2f9f18f5..ce76dc79896192 100644
--- a/src/coreclr/jit/fgdiagnostic.cpp
+++ b/src/coreclr/jit/fgdiagnostic.cpp
@@ -734,12 +734,14 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
const bool includeLoops = (JitConfig.JitDumpFgLoops() != 0) && !compIsForInlining() && (phase < PHASE_RATIONALIZE);
const bool constrained = JitConfig.JitDumpFgConstrained() != 0;
const bool useBlockId = JitConfig.JitDumpFgBlockID() != 0;
+ const bool displayBlockFlags = JitConfig.JitDumpFgBlockFlags() != 0;
#else // !DEBUG
- const bool createDotFile = true;
- const bool includeEH = false;
- const bool includeLoops = false;
- const bool constrained = true;
- const bool useBlockId = false;
+ const bool createDotFile = true;
+ const bool includeEH = false;
+ const bool includeLoops = false;
+ const bool constrained = true;
+ const bool useBlockId = false;
+ const bool displayBlockFlags = false;
#endif // !DEBUG
FILE* fgxFile = fgOpenFlowGraphFile(&dontClose, phase, pos, createDotFile ? W("dot") : W("fgx"));
@@ -866,6 +868,43 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
fprintf(fgxFile, FMT_BB, block->bbNum);
}
+ if (displayBlockFlags)
+ {
+ // Don't display the `[` `]` unless we're going to display something.
+ const BasicBlockFlags allDisplayedBlockFlags = BBF_TRY_BEG | BBF_FUNCLET_BEG | BBF_RUN_RARELY |
+ BBF_LOOP_HEAD | BBF_LOOP_PREHEADER | BBF_LOOP_ALIGN;
+ if (block->bbFlags & allDisplayedBlockFlags)
+ {
+ // Display a very few, useful, block flags
+ fprintf(fgxFile, " [");
+ if (block->bbFlags & BBF_TRY_BEG)
+ {
+ fprintf(fgxFile, "T");
+ }
+ if (block->bbFlags & BBF_FUNCLET_BEG)
+ {
+ fprintf(fgxFile, "F");
+ }
+ if (block->bbFlags & BBF_RUN_RARELY)
+ {
+ fprintf(fgxFile, "R");
+ }
+ if (block->bbFlags & BBF_LOOP_HEAD)
+ {
+ fprintf(fgxFile, "L");
+ }
+ if (block->bbFlags & BBF_LOOP_PREHEADER)
+ {
+ fprintf(fgxFile, "P");
+ }
+ if (block->bbFlags & BBF_LOOP_ALIGN)
+ {
+ fprintf(fgxFile, "A");
+ }
+ fprintf(fgxFile, "]");
+ }
+ }
+
if (block->bbJumpKind == BBJ_COND)
{
fprintf(fgxFile, "\\n");
@@ -1636,6 +1675,12 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
if (includeLoops)
{
+#ifdef DEBUG
+ const bool displayLoopFlags = JitConfig.JitDumpFgLoopFlags() != 0;
+#else // !DEBUG
+ const bool displayLoopFlags = false;
+#endif // !DEBUG
+
char name[30];
for (unsigned loopNum = 0; loopNum < optLoopCount; loopNum++)
{
@@ -1644,7 +1689,24 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
{
continue;
}
+
sprintf_s(name, sizeof(name), FMT_LP, loopNum);
+
+ if (displayLoopFlags)
+ {
+ // Display a very few, useful, loop flags
+ strcat_s(name, sizeof(name), " [");
+ if (loop.lpFlags & LoopFlags::LPFLG_ITER)
+ {
+ strcat_s(name, sizeof(name), "I");
+ }
+ if (loop.lpFlags & LoopFlags::LPFLG_HAS_PREHEAD)
+ {
+ strcat_s(name, sizeof(name), "P");
+ }
+ strcat_s(name, sizeof(name), "]");
+ }
+
rgnGraph.Insert(name, RegionGraph::RegionType::Loop, loop.lpTop, loop.lpBottom);
}
}
@@ -2804,7 +2866,7 @@ void Compiler::fgDebugCheckBBlist(bool checkBBNum /* = false */, bool checkBBRef
#ifndef JIT32_GCENCODER
copiedForGenericsCtxt = ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0);
#else // JIT32_GCENCODER
- copiedForGenericsCtxt = false;
+ copiedForGenericsCtxt = false;
#endif // JIT32_GCENCODER
// This if only in support of the noway_asserts it contains.
diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp
index cf73fa123e6fd9..17d13b362d04cf 100644
--- a/src/coreclr/jit/fginline.cpp
+++ b/src/coreclr/jit/fginline.cpp
@@ -1905,7 +1905,7 @@ void Compiler::fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* bloc
GenTree* retExpr = inlineInfo->retExpr;
if (retExpr != nullptr)
{
- const bool interferesWithReturn = gtHasRef(inlineInfo->retExpr, tmpNum, false);
+ const bool interferesWithReturn = gtHasRef(inlineInfo->retExpr, tmpNum);
noway_assert(!interferesWithReturn);
}
diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp
index e0fdac1da935ca..859ea08aed822e 100644
--- a/src/coreclr/jit/flowgraph.cpp
+++ b/src/coreclr/jit/flowgraph.cpp
@@ -1084,7 +1084,9 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
GenTree* qmarkNode = nullptr;
if (oper == GT_FTN_ADDR)
{
- targetMethodHnd = targetMethod->AsFptrVal()->gtFptrMethod;
+ GenTreeFptrVal* fptrValTree = targetMethod->AsFptrVal();
+ fptrValTree->gtFptrDelegateTarget = true;
+ targetMethodHnd = fptrValTree->gtFptrMethod;
}
else if (oper == GT_CALL && targetMethod->AsCall()->gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
{
@@ -3933,11 +3935,7 @@ void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR)
GenTree* sizeNode = dynBlk->gtDynamicSize;
GenTree* dstAddr = dynBlk->Addr();
GenTree* src = dynBlk->Data();
- bool isReverse = ((dynBlk->gtFlags & GTF_REVERSE_OPS) != 0);
- if (dynBlk->gtEvalSizeFirst)
- {
- fgSetTreeSeqHelper(sizeNode, isLIR);
- }
+ bool isReverse = dynBlk->IsReverseOp();
// We either have a DYN_BLK or a STORE_DYN_BLK. If the latter, we have a
// src (the Data to be stored), and isReverse tells us whether to evaluate
@@ -3951,10 +3949,8 @@ void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR)
{
fgSetTreeSeqHelper(src, isLIR);
}
- if (!dynBlk->gtEvalSizeFirst)
- {
- fgSetTreeSeqHelper(sizeNode, isLIR);
- }
+ fgSetTreeSeqHelper(sizeNode, isLIR);
+
fgSetTreeSeqFinish(dynBlk, isLIR);
return;
}
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 00c58d70bae1d2..7c0f79288f5226 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -1634,262 +1634,70 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK)
return false;
}
-/*****************************************************************************
- *
- * Returns non-zero if the given tree contains a use of a local #lclNum.
- */
-
-// TODO-List-Cleanup: rewrite with a general visitor.
-bool Compiler::gtHasRef(GenTree* tree, ssize_t lclNum, bool defOnly)
+//------------------------------------------------------------------------
+// gtHasRef: Find out whether the given tree contains a local/field.
+//
+// Arguments:
+// tree - tree to find the local in
+// lclNum - the local's number, *or* the handle for the field
+//
+// Return Value:
+// Whether "tree" has any LCL_VAR/LCL_FLD nodes that refer to the
+// local, LHS or RHS, or FIELD nodes with the specified handle.
+//
+// Notes:
+// Does not pay attention to local address nodes.
+//
+/* static */ bool Compiler::gtHasRef(GenTree* tree, ssize_t lclNum)
{
- genTreeOps oper;
- unsigned kind;
-
-AGAIN:
-
- assert(tree);
-
- oper = tree->OperGet();
- kind = tree->OperKind();
-
- /* Is this a constant node? */
-
- if (kind & GTK_CONST)
+ if (tree == nullptr)
{
return false;
}
- /* Is this a leaf node? */
-
- if (kind & GTK_LEAF)
+ if (tree->OperIsLeaf())
{
- if (oper == GT_LCL_VAR)
+ if (tree->OperIs(GT_LCL_VAR, GT_LCL_FLD) && (tree->AsLclVarCommon()->GetLclNum() == (unsigned)lclNum))
{
- if (tree->AsLclVarCommon()->GetLclNum() == (unsigned)lclNum)
- {
- if (!defOnly)
- {
- return true;
- }
- }
+ return true;
}
- else if (oper == GT_RET_EXPR)
+ if (tree->OperIs(GT_RET_EXPR))
{
- return gtHasRef(tree->AsRetExpr()->gtInlineCandidate, lclNum, defOnly);
+ return gtHasRef(tree->AsRetExpr()->gtInlineCandidate, lclNum);
}
return false;
}
- /* Is it a 'simple' unary/binary operator? */
-
- if (kind & GTK_SMPOP)
+ if (tree->OperIsUnary())
{
// Code in importation (see CEE_STFLD in impImportBlockCode), when
// spilling, can pass us "lclNum" that is actually a field handle...
- if (tree->OperIs(GT_FIELD) && (lclNum == (ssize_t)tree->AsField()->gtFldHnd) && !defOnly)
+ if (tree->OperIs(GT_FIELD) && (lclNum == (ssize_t)tree->AsField()->gtFldHnd))
{
return true;
}
- if (tree->gtGetOp2IfPresent())
- {
- if (gtHasRef(tree->AsOp()->gtOp1, lclNum, defOnly))
- {
- return true;
- }
-
- tree = tree->AsOp()->gtOp2;
- goto AGAIN;
- }
- else
- {
- tree = tree->AsOp()->gtOp1;
-
- if (!tree)
- {
- return false;
- }
-
- if (oper == GT_ASG)
- {
- // 'tree' is the gtOp1 of an assignment node. So we can handle
- // the case where defOnly is either true or false.
-
- if (tree->gtOper == GT_LCL_VAR && tree->AsLclVarCommon()->GetLclNum() == (unsigned)lclNum)
- {
- return true;
- }
- else if (tree->gtOper == GT_FIELD && lclNum == (ssize_t)tree->AsField()->gtFldHnd)
- {
- return true;
- }
- }
-
- goto AGAIN;
- }
+ return gtHasRef(tree->AsUnOp()->gtGetOp1(), lclNum);
}
- /* See what kind of a special operator we have here */
-
- switch (oper)
+ if (tree->OperIsBinary())
{
- case GT_CALL:
- if (tree->AsCall()->gtCallThisArg != nullptr)
- {
- if (gtHasRef(tree->AsCall()->gtCallThisArg->GetNode(), lclNum, defOnly))
- {
- return true;
- }
- }
-
- for (GenTreeCall::Use& use : tree->AsCall()->Args())
- {
- if (gtHasRef(use.GetNode(), lclNum, defOnly))
- {
- return true;
- }
- }
-
- for (GenTreeCall::Use& use : tree->AsCall()->LateArgs())
- {
- if (gtHasRef(use.GetNode(), lclNum, defOnly))
- {
- return true;
- }
- }
-
- if (tree->AsCall()->gtControlExpr)
- {
- if (gtHasRef(tree->AsCall()->gtControlExpr, lclNum, defOnly))
- {
- return true;
- }
- }
-
- if (tree->AsCall()->gtCallType == CT_INDIRECT)
- {
- // pinvoke-calli cookie is a constant, or constant indirection
- assert(tree->AsCall()->gtCallCookie == nullptr || tree->AsCall()->gtCallCookie->gtOper == GT_CNS_INT ||
- tree->AsCall()->gtCallCookie->gtOper == GT_IND);
-
- tree = tree->AsCall()->gtCallAddr;
- }
- else
- {
- tree = nullptr;
- }
-
- if (tree)
- {
- goto AGAIN;
- }
-
- break;
-
-#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
-#if defined(FEATURE_SIMD)
- case GT_SIMD:
-#endif
-#if defined(FEATURE_HW_INTRINSICS)
- case GT_HWINTRINSIC:
-#endif
- for (GenTree* operand : tree->AsMultiOp()->Operands())
- {
- if (gtHasRef(operand, lclNum, defOnly))
- {
- return true;
- }
- }
- break;
-#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
-
- case GT_ARR_ELEM:
- if (gtHasRef(tree->AsArrElem()->gtArrObj, lclNum, defOnly))
- {
- return true;
- }
-
- unsigned dim;
- for (dim = 0; dim < tree->AsArrElem()->gtArrRank; dim++)
- {
- if (gtHasRef(tree->AsArrElem()->gtArrInds[dim], lclNum, defOnly))
- {
- return true;
- }
- }
-
- break;
-
- case GT_ARR_OFFSET:
- if (gtHasRef(tree->AsArrOffs()->gtOffset, lclNum, defOnly) ||
- gtHasRef(tree->AsArrOffs()->gtIndex, lclNum, defOnly) ||
- gtHasRef(tree->AsArrOffs()->gtArrObj, lclNum, defOnly))
- {
- return true;
- }
- break;
-
- case GT_PHI:
- for (GenTreePhi::Use& use : tree->AsPhi()->Uses())
- {
- if (gtHasRef(use.GetNode(), lclNum, defOnly))
- {
- return true;
- }
- }
- break;
-
- case GT_FIELD_LIST:
- for (GenTreeFieldList::Use& use : tree->AsFieldList()->Uses())
- {
- if (gtHasRef(use.GetNode(), lclNum, defOnly))
- {
- return true;
- }
- }
- break;
-
- case GT_CMPXCHG:
- if (gtHasRef(tree->AsCmpXchg()->gtOpLocation, lclNum, defOnly))
- {
- return true;
- }
- if (gtHasRef(tree->AsCmpXchg()->gtOpValue, lclNum, defOnly))
- {
- return true;
- }
- if (gtHasRef(tree->AsCmpXchg()->gtOpComparand, lclNum, defOnly))
- {
- return true;
- }
- break;
+ return gtHasRef(tree->AsOp()->gtGetOp1(), lclNum) || gtHasRef(tree->AsOp()->gtGetOp2(), lclNum);
+ }
- case GT_STORE_DYN_BLK:
- if (gtHasRef(tree->AsDynBlk()->Data(), lclNum, defOnly))
- {
- return true;
- }
- FALLTHROUGH;
- case GT_DYN_BLK:
- if (gtHasRef(tree->AsDynBlk()->Addr(), lclNum, defOnly))
- {
- return true;
- }
- if (gtHasRef(tree->AsDynBlk()->gtDynamicSize, lclNum, defOnly))
- {
- return true;
- }
- break;
+ bool result = false;
+ tree->VisitOperands([lclNum, &result](GenTree* operand) -> GenTree::VisitResult {
+ if (gtHasRef(operand, lclNum))
+ {
+ result = true;
+ return GenTree::VisitResult::Abort;
+ }
- default:
-#ifdef DEBUG
- gtDispTree(tree);
-#endif
- assert(!"unexpected operator");
- }
+ return GenTree::VisitResult::Continue;
+ });
- return false;
+ return result;
}
struct AddrTakenDsc
@@ -2620,29 +2428,58 @@ unsigned Compiler::gtSetMultiOpOrder(GenTreeMultiOp* multiOp)
unsigned level = 0;
unsigned lvl2 = 0;
-#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_XARCH)
- if (multiOp->OperIs(GT_HWINTRINSIC) && (multiOp->GetOperandCount() == 1) &&
- multiOp->AsHWIntrinsic()->OperIsMemoryLoadOrStore())
+#if defined(FEATURE_HW_INTRINSICS)
+ if (multiOp->OperIs(GT_HWINTRINSIC))
{
- costEx = IND_COST_EX;
- costSz = 2;
+ GenTreeHWIntrinsic* hwTree = multiOp->AsHWIntrinsic();
+#if defined(TARGET_XARCH)
+ if ((hwTree->GetOperandCount() == 1) && hwTree->OperIsMemoryLoadOrStore())
+ {
+ costEx = IND_COST_EX;
+ costSz = 2;
- GenTree* addr = multiOp->Op(1)->gtEffectiveVal();
- level = gtSetEvalOrder(addr);
+ GenTree* addr = hwTree->Op(1)->gtEffectiveVal();
+ level = gtSetEvalOrder(addr);
- // See if we can form a complex addressing mode.
- if (addr->OperIs(GT_ADD) && gtMarkAddrMode(addr, &costEx, &costSz, multiOp->TypeGet()))
- {
- // Nothing to do, costs have been set.
+ // See if we can form a complex addressing mode.
+ if (addr->OperIs(GT_ADD) && gtMarkAddrMode(addr, &costEx, &costSz, hwTree->TypeGet()))
+ {
+ // Nothing to do, costs have been set.
+ }
+ else
+ {
+ costEx += addr->GetCostEx();
+ costSz += addr->GetCostSz();
+ }
+
+ hwTree->SetCosts(costEx, costSz);
+ return level;
}
- else
+#endif
+ switch (hwTree->GetHWIntrinsicId())
{
- costEx += addr->GetCostEx();
- costSz += addr->GetCostSz();
+#if defined(TARGET_XARCH)
+ case NI_Vector128_Create:
+ case NI_Vector256_Create:
+#elif defined(TARGET_ARM64)
+ case NI_Vector64_Create:
+ case NI_Vector128_Create:
+#endif
+ {
+ if ((hwTree->GetOperandCount() == 1) && hwTree->Op(1)->OperIsConst())
+ {
+ // Vector.Create(cns) is cheap but not that cheap to be (1,1)
+ costEx = IND_COST_EX;
+ costSz = 2;
+ level = gtSetEvalOrder(hwTree->Op(1));
+ hwTree->SetCosts(costEx, costSz);
+ return level;
+ }
+ break;
+ }
+ default:
+ break;
}
-
- multiOp->SetCosts(costEx, costSz);
- return level;
}
#endif // defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS)
@@ -3947,21 +3784,16 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
}
break;
}
+
+ case NI_System_Object_GetType:
+ // Giving intrinsics a large fixed execution cost is because we'd like to CSE
+ // them, even if they are implemented by calls. This is different from modeling
+ // user calls since we never CSE user calls.
+ costEx = 36;
+ costSz = 4;
+ break;
}
}
- else
- {
- // old style intrinsic (only Object_GetType is expected)
- assert(intrinsic->gtIntrinsicName == NI_Illegal);
- assert(intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType);
-
- // Giving intrinsics a large fixed execution cost is because we'd like to CSE
- // them, even if they are implemented by calls. This is different from modeling
- // user calls since we never CSE user calls.
- costEx = 36;
- costSz = 4;
- break;
- }
level++;
break;
@@ -4841,7 +4673,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
case GT_STORE_DYN_BLK:
case GT_DYN_BLK:
- {
level = gtSetEvalOrder(tree->AsDynBlk()->Addr());
costEx = tree->AsDynBlk()->Addr()->GetCostEx();
costSz = tree->AsDynBlk()->Addr()->GetCostSz();
@@ -4854,45 +4685,11 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
costSz += tree->AsDynBlk()->Data()->GetCostSz();
}
- unsigned sizeLevel = gtSetEvalOrder(tree->AsDynBlk()->gtDynamicSize);
-
- // Determine whether the size node should be evaluated first.
- // We would like to do this if the sizeLevel is larger than the current level,
- // but we have to ensure that we obey ordering constraints.
- if (tree->AsDynBlk()->gtEvalSizeFirst != (level < sizeLevel))
- {
- bool canChange = true;
-
- GenTree* sizeNode = tree->AsDynBlk()->gtDynamicSize;
- GenTree* dst = tree->AsDynBlk()->Addr();
- GenTree* src = tree->AsDynBlk()->Data();
-
- if (tree->AsDynBlk()->gtEvalSizeFirst)
- {
- canChange = gtCanSwapOrder(sizeNode, dst);
- if (canChange && (src != nullptr))
- {
- canChange = gtCanSwapOrder(sizeNode, src);
- }
- }
- else
- {
- canChange = gtCanSwapOrder(dst, sizeNode);
- if (canChange && (src != nullptr))
- {
- gtCanSwapOrder(src, sizeNode);
- }
- }
- if (canChange)
- {
- tree->AsDynBlk()->gtEvalSizeFirst = (level < sizeLevel);
- }
- }
- level = max(level, sizeLevel);
+ lvl2 = gtSetEvalOrder(tree->AsDynBlk()->gtDynamicSize);
+ level = max(level, lvl2);
costEx += tree->AsDynBlk()->gtDynamicSize->GetCostEx();
costSz += tree->AsDynBlk()->gtDynamicSize->GetCostSz();
- }
- break;
+ break;
default:
JITDUMP("unexpected operator in this tree:\n");
@@ -8605,25 +8402,15 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
return;
case GT_DYN_BLK:
- {
- GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
- m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
+ m_edge = &m_node->AsDynBlk()->Addr();
assert(*m_edge != nullptr);
m_advance = &GenTreeUseEdgeIterator::AdvanceDynBlk;
- }
return;
case GT_STORE_DYN_BLK:
{
GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
- if (dynBlock->gtEvalSizeFirst)
- {
- m_edge = &dynBlock->gtDynamicSize;
- }
- else
- {
- m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
- }
+ m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
assert(*m_edge != nullptr);
m_advance = &GenTreeUseEdgeIterator::AdvanceStoreDynBlk;
@@ -8712,7 +8499,7 @@ void GenTreeUseEdgeIterator::AdvanceDynBlk()
{
GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
- m_edge = dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
+ m_edge = &dynBlock->gtDynamicSize;
assert(*m_edge != nullptr);
m_advance = &GenTreeUseEdgeIterator::Terminate;
}
@@ -8720,43 +8507,21 @@ void GenTreeUseEdgeIterator::AdvanceDynBlk()
//------------------------------------------------------------------------
// GenTreeUseEdgeIterator::AdvanceStoreDynBlk: produces the next operand of a StoreDynBlk node and advances the state.
//
-// These nodes are moderately complicated but rare enough that templating this function is probably not
-// worth the extra complexity.
-//
void GenTreeUseEdgeIterator::AdvanceStoreDynBlk()
{
GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
- if (dynBlock->gtEvalSizeFirst)
- {
- switch (m_state)
- {
- case 0:
- m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
- m_state = 1;
- break;
- case 1:
- m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
- m_advance = &GenTreeUseEdgeIterator::Terminate;
- break;
- default:
- unreached();
- }
- }
- else
+ switch (m_state)
{
- switch (m_state)
- {
- case 0:
- m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
- m_state = 1;
- break;
- case 1:
- m_edge = &dynBlock->gtDynamicSize;
- m_advance = &GenTreeUseEdgeIterator::Terminate;
- break;
- default:
- unreached();
- }
+ case 0:
+ m_edge = dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
+ m_state = 1;
+ break;
+ case 1:
+ m_edge = &dynBlock->gtDynamicSize;
+ m_advance = &GenTreeUseEdgeIterator::Terminate;
+ break;
+ default:
+ unreached();
}
assert(*m_edge != nullptr);
@@ -10454,6 +10219,9 @@ void Compiler::gtDispConst(GenTree* tree)
case GTF_ICON_BBC_PTR:
printf(" bbc");
break;
+ case GTF_ICON_STATIC_BOX_PTR:
+ printf(" static box ptr");
+ break;
default:
printf(" UNKNOWN");
break;
@@ -11018,101 +10786,96 @@ void Compiler::gtDispTree(GenTree* tree,
{
GenTreeIntrinsic* intrinsic = tree->AsIntrinsic();
- if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
- {
- assert(intrinsic->gtIntrinsicName == NI_Illegal);
- printf(" objGetType");
- }
- else
+ assert(intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Illegal);
+ switch (intrinsic->gtIntrinsicName)
{
- assert(intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Illegal);
- switch (intrinsic->gtIntrinsicName)
- {
- case NI_System_Math_Abs:
- printf(" abs");
- break;
- case NI_System_Math_Acos:
- printf(" acos");
- break;
- case NI_System_Math_Acosh:
- printf(" acosh");
- break;
- case NI_System_Math_Asin:
- printf(" asin");
- break;
- case NI_System_Math_Asinh:
- printf(" asinh");
- break;
- case NI_System_Math_Atan:
- printf(" atan");
- break;
- case NI_System_Math_Atanh:
- printf(" atanh");
- break;
- case NI_System_Math_Atan2:
- printf(" atan2");
- break;
- case NI_System_Math_Cbrt:
- printf(" cbrt");
- break;
- case NI_System_Math_Ceiling:
- printf(" ceiling");
- break;
- case NI_System_Math_Cos:
- printf(" cos");
- break;
- case NI_System_Math_Cosh:
- printf(" cosh");
- break;
- case NI_System_Math_Exp:
- printf(" exp");
- break;
- case NI_System_Math_Floor:
- printf(" floor");
- break;
- case NI_System_Math_FMod:
- printf(" fmod");
- break;
- case NI_System_Math_FusedMultiplyAdd:
- printf(" fma");
- break;
- case NI_System_Math_ILogB:
- printf(" ilogb");
- break;
- case NI_System_Math_Log:
- printf(" log");
- break;
- case NI_System_Math_Log2:
- printf(" log2");
- break;
- case NI_System_Math_Log10:
- printf(" log10");
- break;
- case NI_System_Math_Pow:
- printf(" pow");
- break;
- case NI_System_Math_Round:
- printf(" round");
- break;
- case NI_System_Math_Sin:
- printf(" sin");
- break;
- case NI_System_Math_Sinh:
- printf(" sinh");
- break;
- case NI_System_Math_Sqrt:
- printf(" sqrt");
- break;
- case NI_System_Math_Tan:
- printf(" tan");
- break;
- case NI_System_Math_Tanh:
- printf(" tanh");
- break;
+ case NI_System_Math_Abs:
+ printf(" abs");
+ break;
+ case NI_System_Math_Acos:
+ printf(" acos");
+ break;
+ case NI_System_Math_Acosh:
+ printf(" acosh");
+ break;
+ case NI_System_Math_Asin:
+ printf(" asin");
+ break;
+ case NI_System_Math_Asinh:
+ printf(" asinh");
+ break;
+ case NI_System_Math_Atan:
+ printf(" atan");
+ break;
+ case NI_System_Math_Atanh:
+ printf(" atanh");
+ break;
+ case NI_System_Math_Atan2:
+ printf(" atan2");
+ break;
+ case NI_System_Math_Cbrt:
+ printf(" cbrt");
+ break;
+ case NI_System_Math_Ceiling:
+ printf(" ceiling");
+ break;
+ case NI_System_Math_Cos:
+ printf(" cos");
+ break;
+ case NI_System_Math_Cosh:
+ printf(" cosh");
+ break;
+ case NI_System_Math_Exp:
+ printf(" exp");
+ break;
+ case NI_System_Math_Floor:
+ printf(" floor");
+ break;
+ case NI_System_Math_FMod:
+ printf(" fmod");
+ break;
+ case NI_System_Math_FusedMultiplyAdd:
+ printf(" fma");
+ break;
+ case NI_System_Math_ILogB:
+ printf(" ilogb");
+ break;
+ case NI_System_Math_Log:
+ printf(" log");
+ break;
+ case NI_System_Math_Log2:
+ printf(" log2");
+ break;
+ case NI_System_Math_Log10:
+ printf(" log10");
+ break;
+ case NI_System_Math_Pow:
+ printf(" pow");
+ break;
+ case NI_System_Math_Round:
+ printf(" round");
+ break;
+ case NI_System_Math_Sin:
+ printf(" sin");
+ break;
+ case NI_System_Math_Sinh:
+ printf(" sinh");
+ break;
+ case NI_System_Math_Sqrt:
+ printf(" sqrt");
+ break;
+ case NI_System_Math_Tan:
+ printf(" tan");
+ break;
+ case NI_System_Math_Tanh:
+ printf(" tanh");
+ break;
+ case NI_System_Object_GetType:
+ printf(" objGetType");
+ break;
- default:
- unreached();
- }
+ default:
+ unreached();
}
}
@@ -15373,13 +15136,13 @@ Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
}
else if (tree->AsCall()->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
{
- if (info.compCompHnd->getIntrinsicID(tree->AsCall()->gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
+ if (lookupNamedIntrinsic(tree->AsCall()->gtCallMethHnd) == NI_System_Object_GetType)
{
return TPK_GetType;
}
}
}
- else if ((tree->gtOper == GT_INTRINSIC) && (tree->AsIntrinsic()->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
+ else if ((tree->gtOper == GT_INTRINSIC) && (tree->AsIntrinsic()->gtIntrinsicName == NI_System_Object_GetType))
{
return TPK_GetType;
}
@@ -16964,7 +16727,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
{
GenTreeIntrinsic* intrinsic = obj->AsIntrinsic();
- if (intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)
+ if (intrinsic->gtIntrinsicName == NI_System_Object_GetType)
{
CORINFO_CLASS_HANDLE runtimeType = info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
assert(runtimeType != NO_CLASS_HANDLE);
diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h
index 1a0865073982dc..1cad150ac5e35c 100644
--- a/src/coreclr/jit/gentree.h
+++ b/src/coreclr/jit/gentree.h
@@ -542,27 +542,28 @@ enum GenTreeFlags : unsigned int
GTF_BOX_VALUE = 0x80000000, // GT_BOX -- "box" is on a value type
- GTF_ICON_HDL_MASK = 0xF0000000, // Bits used by handle types below
- GTF_ICON_SCOPE_HDL = 0x10000000, // GT_CNS_INT -- constant is a scope handle
- GTF_ICON_CLASS_HDL = 0x20000000, // GT_CNS_INT -- constant is a class handle
- GTF_ICON_METHOD_HDL = 0x30000000, // GT_CNS_INT -- constant is a method handle
- GTF_ICON_FIELD_HDL = 0x40000000, // GT_CNS_INT -- constant is a field handle
- GTF_ICON_STATIC_HDL = 0x50000000, // GT_CNS_INT -- constant is a handle to static data
- GTF_ICON_STR_HDL = 0x60000000, // GT_CNS_INT -- constant is a string handle
- GTF_ICON_CONST_PTR = 0x70000000, // GT_CNS_INT -- constant is a pointer to immutable data, (e.g. IAT_PPVALUE)
- GTF_ICON_GLOBAL_PTR = 0x80000000, // GT_CNS_INT -- constant is a pointer to mutable data (e.g. from the VM state)
- GTF_ICON_VARG_HDL = 0x90000000, // GT_CNS_INT -- constant is a var arg cookie handle
- GTF_ICON_PINVKI_HDL = 0xA0000000, // GT_CNS_INT -- constant is a pinvoke calli handle
- GTF_ICON_TOKEN_HDL = 0xB0000000, // GT_CNS_INT -- constant is a token handle (other than class, method or field)
- GTF_ICON_TLS_HDL = 0xC0000000, // GT_CNS_INT -- constant is a TLS ref with offset
- GTF_ICON_FTN_ADDR = 0xD0000000, // GT_CNS_INT -- constant is a function address
- GTF_ICON_CIDMID_HDL = 0xE0000000, // GT_CNS_INT -- constant is a class ID or a module ID
- GTF_ICON_BBC_PTR = 0xF0000000, // GT_CNS_INT -- constant is a basic block count pointer
-
- GTF_ICON_FIELD_OFF = 0x08000000, // GT_CNS_INT -- constant is a field offset
- GTF_ICON_SIMD_COUNT = 0x04000000, // GT_CNS_INT -- constant is Vector.Count
-
- GTF_ICON_INITCLASS = 0x02000000, // GT_CNS_INT -- Constant is used to access a static that requires preceding
+ GTF_ICON_HDL_MASK = 0xFF000000, // Bits used by handle types below
+ GTF_ICON_SCOPE_HDL = 0x01000000, // GT_CNS_INT -- constant is a scope handle
+ GTF_ICON_CLASS_HDL = 0x02000000, // GT_CNS_INT -- constant is a class handle
+ GTF_ICON_METHOD_HDL = 0x03000000, // GT_CNS_INT -- constant is a method handle
+ GTF_ICON_FIELD_HDL = 0x04000000, // GT_CNS_INT -- constant is a field handle
+ GTF_ICON_STATIC_HDL = 0x05000000, // GT_CNS_INT -- constant is a handle to static data
+ GTF_ICON_STR_HDL = 0x06000000, // GT_CNS_INT -- constant is a string handle
+ GTF_ICON_CONST_PTR = 0x07000000, // GT_CNS_INT -- constant is a pointer to immutable data, (e.g. IAT_PPVALUE)
+ GTF_ICON_GLOBAL_PTR = 0x08000000, // GT_CNS_INT -- constant is a pointer to mutable data (e.g. from the VM state)
+ GTF_ICON_VARG_HDL = 0x09000000, // GT_CNS_INT -- constant is a var arg cookie handle
+ GTF_ICON_PINVKI_HDL = 0x0A000000, // GT_CNS_INT -- constant is a pinvoke calli handle
+ GTF_ICON_TOKEN_HDL = 0x0B000000, // GT_CNS_INT -- constant is a token handle (other than class, method or field)
+ GTF_ICON_TLS_HDL = 0x0C000000, // GT_CNS_INT -- constant is a TLS ref with offset
+ GTF_ICON_FTN_ADDR = 0x0D000000, // GT_CNS_INT -- constant is a function address
+ GTF_ICON_CIDMID_HDL = 0x0E000000, // GT_CNS_INT -- constant is a class ID or a module ID
+ GTF_ICON_BBC_PTR = 0x0F000000, // GT_CNS_INT -- constant is a basic block count pointer
+ GTF_ICON_STATIC_BOX_PTR = 0x10000000, // GT_CNS_INT -- constant is an address of the box for a STATIC_IN_HEAP field
+
+ // GTF_ICON_REUSE_REG_VAL = 0x00800000 // GT_CNS_INT -- GTF_REUSE_REG_VAL, defined above
+ GTF_ICON_FIELD_OFF = 0x00400000, // GT_CNS_INT -- constant is a field offset
+ GTF_ICON_SIMD_COUNT = 0x00200000, // GT_CNS_INT -- constant is Vector.Count
+ GTF_ICON_INITCLASS = 0x00100000, // GT_CNS_INT -- Constant is used to access a static that requires preceding
// class/static init helper. In some cases, the constant is
// the address of the static field itself, and in other cases
// there's an extra layer of indirection and it is the address
@@ -2271,9 +2272,8 @@ struct GenTree
// hot code, as it affords better opportunities for inlining and acheives shorter dynamic path lengths when
// deciding how operands need to be accessed.
//
- // Note that this function does not respect `GTF_REVERSE_OPS` and `gtEvalSizeFirst`. This is always safe in LIR,
- // but may be dangerous in HIR if for some reason you need to visit operands in the order in which they will
- // execute.
+ // Note that this function does not respect `GTF_REVERSE_OPS`. This is always safe in LIR, but may be dangerous
+ // in HIR if for some reason you need to visit operands in the order in which they will execute.
template
void VisitOperands(TVisitor visitor);
@@ -4965,11 +4965,14 @@ struct GenTreeFptrVal : public GenTree
{
CORINFO_METHOD_HANDLE gtFptrMethod;
+ bool gtFptrDelegateTarget;
+
#ifdef FEATURE_READYTORUN
CORINFO_CONST_LOOKUP gtEntryPoint;
#endif
- GenTreeFptrVal(var_types type, CORINFO_METHOD_HANDLE meth) : GenTree(GT_FTN_ADDR, type), gtFptrMethod(meth)
+ GenTreeFptrVal(var_types type, CORINFO_METHOD_HANDLE meth)
+ : GenTree(GT_FTN_ADDR, type), gtFptrMethod(meth), gtFptrDelegateTarget(false)
{
#ifdef FEATURE_READYTORUN
gtEntryPoint.addr = nullptr;
@@ -6254,10 +6257,9 @@ struct GenTreeDynBlk : public GenTreeBlk
{
public:
GenTree* gtDynamicSize;
- bool gtEvalSizeFirst;
GenTreeDynBlk(GenTree* addr, GenTree* dynamicSize)
- : GenTreeBlk(GT_DYN_BLK, TYP_STRUCT, addr, nullptr), gtDynamicSize(dynamicSize), gtEvalSizeFirst(false)
+ : GenTreeBlk(GT_DYN_BLK, TYP_STRUCT, addr, nullptr), gtDynamicSize(dynamicSize)
{
// Conservatively the 'addr' could be null or point into the global heap.
gtFlags |= GTF_EXCEPT | GTF_GLOB_REF;
@@ -6624,7 +6626,7 @@ struct Statement
// The statement nodes are doubly-linked. The first statement node in a block points
// to the last node in the block via its `m_prev` link. Note that the last statement node
- // does not point to the first: it's `m_next == nullptr`; that is, the list is not fully circular.
+ // does not point to the first: it has `m_next == nullptr`; that is, the list is not fully circular.
Statement* m_next;
Statement* m_prev;
diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h
index ad45f810ad85d7..6f6462d6743bd0 100644
--- a/src/coreclr/jit/gtlist.h
+++ b/src/coreclr/jit/gtlist.h
@@ -292,7 +292,7 @@ GTNODE(JMPTABLE , GenTree ,0, (GTK_LEAF|GTK_NOCONTAIN)) // Ge
GTNODE(SWITCH_TABLE , GenTreeOp ,0, (GTK_BINOP|GTK_NOVALUE)) // Jump Table based switch construct
#ifdef TARGET_ARM64
GTNODE(ADDEX, GenTreeOp ,0, GTK_BINOP) // Add with sign/zero extension
-GTNODE(BFIZ , GenTreeOp ,0, GTK_BINOP) // Bitfield Insert in Zero
+GTNODE(BFIZ , GenTreeOp ,0, GTK_BINOP) // Bitfield Insert in Zero
#endif
//-----------------------------------------------------------------------------
diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp
index 7fea81a34e2c12..1a08a26f78dc9e 100644
--- a/src/coreclr/jit/hwintrinsicarm64.cpp
+++ b/src/coreclr/jit/hwintrinsicarm64.cpp
@@ -308,8 +308,22 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
var_types retType,
unsigned simdSize)
{
- HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic);
- int numArgs = sig->numArgs;
+ const HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic);
+ const int numArgs = sig->numArgs;
+
+ // The vast majority of "special" intrinsics are Vector64/Vector128 methods.
+ // The only exception is ArmBase.Yield which should be treated differently.
+ if (intrinsic == NI_ArmBase_Yield)
+ {
+ assert(sig->numArgs == 0);
+ assert(JITtype2varType(sig->retType) == TYP_VOID);
+ assert(simdSize == 0);
+
+ return gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic);
+ }
+
+ assert(category != HW_Category_Scalar);
+ assert(!HWIntrinsicInfo::isScalarIsa(HWIntrinsicInfo::lookupIsa(intrinsic)));
if (!featureSIMD || !IsBaselineSimdIsaSupported())
{
@@ -318,13 +332,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
assert(numArgs >= 0);
- var_types simdBaseType = TYP_UNKNOWN;
-
- if (intrinsic != NI_ArmBase_Yield)
- {
- simdBaseType = JitType2PreciseVarType(simdBaseJitType);
- assert(varTypeIsArithmetic(simdBaseType));
- }
+ const var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
+ assert(varTypeIsArithmetic(simdBaseType));
GenTree* retNode = nullptr;
GenTree* op1 = nullptr;
@@ -333,16 +342,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic,
switch (intrinsic)
{
- case NI_ArmBase_Yield:
- {
- assert(sig->numArgs == 0);
- assert(JITtype2varType(sig->retType) == TYP_VOID);
- assert(simdSize == 0);
-
- retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic);
- break;
- }
-
case NI_Vector64_Abs:
case NI_Vector128_Abs:
{
diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp
index bb6a6daa815d8b..2bbe2835816fcf 100644
--- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp
+++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp
@@ -2034,9 +2034,9 @@ void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node)
NamedIntrinsic intrinsicId = node->GetHWIntrinsicId();
var_types baseType = node->GetSimdBaseType();
emitAttr attr = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->GetSimdSize()));
- instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); // 213 form
- instruction _132form = (instruction)(ins - 1);
- instruction _231form = (instruction)(ins + 1);
+ instruction _213form = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); // 213 form
+ instruction _132form = (instruction)(_213form - 1);
+ instruction _231form = (instruction)(_213form + 1);
GenTree* op1 = node->Op(1);
GenTree* op2 = node->Op(2);
GenTree* op3 = node->Op(3);
@@ -2058,57 +2058,82 @@ void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node)
// Intrinsics with CopyUpperBits semantics cannot have op1 be contained
assert(!copiesUpperBits || !op1->isContained());
+ // We need to keep this in sync with lsraxarch.cpp
+ // Ideally we'd actually swap the operands in lsra and simplify codegen
+ // but its a bit more complicated to do so for many operands as well
+ // as being complicated to tell codegen how to pick the right instruction
+
+ instruction ins = INS_invalid;
+
if (op1->isContained() || op1->isUsedFromSpillTemp())
{
+ // targetReg == op3NodeReg or targetReg == ?
+ // op3 = ([op1] * op2) + op3
+ // 231 form: XMM1 = (XMM2 * [XMM3]) + XMM1
+ ins = _231form;
+ std::swap(emitOp1, emitOp3);
+
if (targetReg == op2NodeReg)
{
- std::swap(emitOp1, emitOp2);
// op2 = ([op1] * op2) + op3
// 132 form: XMM1 = (XMM1 * [XMM3]) + XMM2
ins = _132form;
- std::swap(emitOp2, emitOp3);
+ std::swap(emitOp1, emitOp2);
}
- else
+ }
+ else if (op3->isContained() || op3->isUsedFromSpillTemp())
+ {
+ // targetReg could be op1NodeReg, op2NodeReg, or not equal to any op
+ // op1 = (op1 * op2) + [op3] or op2 = (op1 * op2) + [op3]
+ // ? = (op1 * op2) + [op3] or ? = (op1 * op2) + op3
+ // 213 form: XMM1 = (XMM2 * XMM1) + [XMM3]
+ ins = _213form;
+
+ if (!copiesUpperBits && (targetReg == op2NodeReg))
{
- // targetReg == op3NodeReg or targetReg == ?
- // op3 = ([op1] * op2) + op3
- // 231 form: XMM1 = (XMM2 * [XMM3]) + XMM1
- ins = _231form;
- std::swap(emitOp1, emitOp3);
+ // op2 = (op1 * op2) + [op3]
+ // 213 form: XMM1 = (XMM2 * XMM1) + [XMM3]
+ std::swap(emitOp1, emitOp2);
}
}
else if (op2->isContained() || op2->isUsedFromSpillTemp())
{
+ // targetReg == op1NodeReg or targetReg == ?
+ // op1 = (op1 * [op2]) + op3
+ // 132 form: XMM1 = (XMM1 * [XMM3]) + XMM2
+ ins = _132form;
+ std::swap(emitOp2, emitOp3);
+
if (!copiesUpperBits && (targetReg == op3NodeReg))
{
// op3 = (op1 * [op2]) + op3
// 231 form: XMM1 = (XMM2 * [XMM3]) + XMM1
ins = _231form;
- std::swap(emitOp1, emitOp3);
- }
- else
- {
- // targetReg == op1NodeReg or targetReg == ?
- // op1 = (op1 * [op2]) + op3
- // 132 form: XMM1 = (XMM1 * [XMM3]) + XMM2
- ins = _132form;
+ std::swap(emitOp1, emitOp2);
}
- std::swap(emitOp2, emitOp3);
}
else
{
- // targetReg could be op1NodeReg, op2NodeReg, or not equal to any op
- // op1 = (op1 * op2) + [op3] or op2 = (op1 * op2) + [op3]
- // ? = (op1 * op2) + [op3] or ? = (op1 * op2) + op3
- // 213 form: XMM1 = (XMM2 * XMM1) + [XMM3]
- if (!copiesUpperBits && (targetReg == op2NodeReg))
+ // When we don't have a contained operand we still want to
+ // preference based on the target register if possible.
+
+ if (targetReg == op2NodeReg)
{
- // op2 = (op1 * op2) + [op3]
- // 213 form: XMM1 = (XMM2 * XMM1) + [XMM3]
+ ins = _213form;
std::swap(emitOp1, emitOp2);
}
+ else if (targetReg == op3NodeReg)
+ {
+ ins = _231form;
+ std::swap(emitOp1, emitOp3);
+ }
+ else
+ {
+ ins = _213form;
+ }
}
+ assert(ins != INS_invalid);
genHWIntrinsic_R_R_R_RM(ins, attr, targetReg, emitOp1->GetRegNum(), emitOp2->GetRegNum(), emitOp3);
genProduceReg(node);
}
diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h
index c7e49b91a05be8..65879aff4024c3 100644
--- a/src/coreclr/jit/hwintrinsiclistarm64.h
+++ b/src/coreclr/jit/hwintrinsiclistarm64.h
@@ -627,7 +627,7 @@ HARDWARE_INTRINSIC(Aes, PolynomialMultiplyWideningUpper,
// Base Intrinsics
HARDWARE_INTRINSIC(ArmBase, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoFloatingPointUsed)
HARDWARE_INTRINSIC(ArmBase, ReverseElementBits, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed)
-HARDWARE_INTRINSIC(ArmBase, Yield, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport)
+HARDWARE_INTRINSIC(ArmBase, Yield, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoFloatingPointUsed|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport)
// ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
// ISA Function name SIMD size Number of arguments Instructions Category Flags
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 70a5cf39b544a2..dc4f56eb4b469f 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -508,7 +508,7 @@ inline void Compiler::impAppendStmtCheck(Statement* stmt, unsigned chkLevel)
unsigned lclNum = tree->AsOp()->gtOp1->AsLclVarCommon()->GetLclNum();
for (unsigned level = 0; level < chkLevel; level++)
{
- assert(!gtHasRef(verCurrentState.esStack[level].val, lclNum, false));
+ assert(!gtHasRef(verCurrentState.esStack[level].val, lclNum));
assert(!lvaTable[lclNum].IsAddressExposed() ||
(verCurrentState.esStack[level].val->gtFlags & GTF_SIDE_EFFECT) == 0);
}
@@ -2757,7 +2757,7 @@ void Compiler::impSpillLclRefs(ssize_t lclNum)
/* Skip the tree if it doesn't have an affected reference,
unless xcptnCaught */
- if (xcptnCaught || gtHasRef(tree, lclNum, false))
+ if (xcptnCaught || gtHasRef(tree, lclNum))
{
impSpillStackEntry(level, BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impSpillLclRefs"));
}
@@ -3648,17 +3648,8 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
const char* Compiler::impGetIntrinsicName(CorInfoIntrinsics intrinsicID)
{
static const char* const intrinsicNameMap[CORINFO_INTRINSIC_Count] = {
- "CORINFO_INTRINSIC_Array_Get",
- "CORINFO_INTRINSIC_Array_Address",
- "CORINFO_INTRINSIC_Array_Set",
- "CORINFO_INTRINSIC_RTH_GetValueInternal",
- "CORINFO_INTRINSIC_Object_GetType",
- "CORINFO_INTRINSIC_StubHelpers_GetStubContext",
- "CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr",
- "CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress",
- "CORINFO_INTRINSIC_ByReference_Ctor",
- "CORINFO_INTRINSIC_ByReference_Value",
- "CORINFO_INTRINSIC_GetRawHandle",
+ "CORINFO_INTRINSIC_Array_Get", "CORINFO_INTRINSIC_Array_Address", "CORINFO_INTRINSIC_Array_Set",
+ "CORINFO_INTRINSIC_ByReference_Ctor", "CORINFO_INTRINSIC_ByReference_Value", "CORINFO_INTRINSIC_GetRawHandle",
};
if ((0 <= intrinsicID) && (intrinsicID < CORINFO_INTRINSIC_Count))
@@ -3844,6 +3835,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
CORINFO_THIS_TRANSFORM constraintCallThisTransform,
CorInfoIntrinsics* pIntrinsicID,
+ NamedIntrinsic* pIntrinsicName,
bool* isSpecialIntrinsic)
{
assert((methodFlags & (CORINFO_FLG_INTRINSIC | CORINFO_FLG_JIT_INTRINSIC)) != 0);
@@ -3919,24 +3911,16 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
}
}
- *pIntrinsicID = intrinsicID;
+ *pIntrinsicID = intrinsicID;
+ *pIntrinsicName = ni;
- if (intrinsicID == CORINFO_INTRINSIC_StubHelpers_GetStubContext)
+ if (ni == NI_System_StubHelpers_GetStubContext)
{
// must be done regardless of DbgCode and MinOpts
return gtNewLclvNode(lvaStubArgumentVar, TYP_I_IMPL);
}
-#ifdef TARGET_64BIT
- if (intrinsicID == CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr)
- {
- // must be done regardless of DbgCode and MinOpts
- return gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaStubArgumentVar, TYP_I_IMPL));
- }
-#else
- assert(intrinsicID != CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr);
-#endif
- if (intrinsicID == CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress)
+ if (ni == NI_System_StubHelpers_NextCallReturnAddress)
{
// For now we just avoid inlining anything into these methods since
// this intrinsic is only rarely used. We could do this better if we
@@ -3982,127 +3966,6 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
retNode = impArrayAccessIntrinsic(clsHnd, sig, memberRef, readonlyCall, intrinsicID);
break;
- case CORINFO_INTRINSIC_RTH_GetValueInternal:
- op1 = impStackTop(0).val;
- if (op1->gtOper == GT_CALL && (op1->AsCall()->gtCallType == CT_HELPER) &&
- gtIsTypeHandleToRuntimeTypeHandleHelper(op1->AsCall()))
- {
- // Old tree
- // Helper-RuntimeTypeHandle -> TreeToGetNativeTypeHandle
- //
- // New tree
- // TreeToGetNativeTypeHandle
-
- // Remove call to helper and return the native TypeHandle pointer that was the parameter
- // to that helper.
-
- op1 = impPopStack().val;
-
- // Get native TypeHandle argument to old helper
- GenTreeCall::Use* arg = op1->AsCall()->gtCallArgs;
- assert(arg->GetNext() == nullptr);
- op1 = arg->GetNode();
- retNode = op1;
- }
- // Call the regular function.
- break;
-
- case CORINFO_INTRINSIC_Object_GetType:
- {
- JITDUMP("\n impIntrinsic: call to Object.GetType\n");
- op1 = impStackTop(0).val;
-
- // If we're calling GetType on a boxed value, just get the type directly.
- if (op1->IsBoxedValue())
- {
- JITDUMP("Attempting to optimize box(...).getType() to direct type construction\n");
-
- // Try and clean up the box. Obtain the handle we
- // were going to pass to the newobj.
- GenTree* boxTypeHandle = gtTryRemoveBoxUpstreamEffects(op1, BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE);
-
- if (boxTypeHandle != nullptr)
- {
- // Note we don't need to play the TYP_STRUCT games here like
- // do for LDTOKEN since the return value of this operator is Type,
- // not RuntimeTypeHandle.
- impPopStack();
- GenTreeCall::Use* helperArgs = gtNewCallArgs(boxTypeHandle);
- GenTree* runtimeType =
- gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
- retNode = runtimeType;
- }
- }
-
- // If we have a constrained callvirt with a "box this" transform
- // we know we have a value class and hence an exact type.
- //
- // If so, instead of boxing and then extracting the type, just
- // construct the type directly.
- if ((retNode == nullptr) && (pConstrainedResolvedToken != nullptr) &&
- (constraintCallThisTransform == CORINFO_BOX_THIS))
- {
- // Ensure this is one of the is simple box cases (in particular, rule out nullables).
- const CorInfoHelpFunc boxHelper = info.compCompHnd->getBoxHelper(pConstrainedResolvedToken->hClass);
- const bool isSafeToOptimize = (boxHelper == CORINFO_HELP_BOX);
-
- if (isSafeToOptimize)
- {
- JITDUMP("Optimizing constrained box-this obj.getType() to direct type construction\n");
- impPopStack();
- GenTree* typeHandleOp =
- impTokenToHandle(pConstrainedResolvedToken, nullptr, true /* mustRestoreHandle */);
- if (typeHandleOp == nullptr)
- {
- assert(compDonotInline());
- return nullptr;
- }
- GenTreeCall::Use* helperArgs = gtNewCallArgs(typeHandleOp);
- GenTree* runtimeType =
- gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
- retNode = runtimeType;
- }
- }
-
-#ifdef DEBUG
- if (retNode != nullptr)
- {
- JITDUMP("Optimized result for call to GetType is\n");
- if (verbose)
- {
- gtDispTree(retNode);
- }
- }
-#endif
-
- // Else expand as an intrinsic, unless the call is constrained,
- // in which case we defer expansion to allow impImportCall do the
- // special constraint processing.
- if ((retNode == nullptr) && (pConstrainedResolvedToken == nullptr))
- {
- JITDUMP("Expanding as special intrinsic\n");
- impPopStack();
- op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, ni, method);
-
- // Set the CALL flag to indicate that the operator is implemented by a call.
- // Set also the EXCEPTION flag because the native implementation of
- // CORINFO_INTRINSIC_Object_GetType intrinsic can throw NullReferenceException.
- op1->gtFlags |= (GTF_CALL | GTF_EXCEPT);
- retNode = op1;
- // Might be further optimizable, so arrange to leave a mark behind
- isSpecial = true;
- }
-
- if (retNode == nullptr)
- {
- JITDUMP("Leaving as normal call\n");
- // Might be further optimizable, so arrange to leave a mark behind
- isSpecial = true;
- }
-
- break;
- }
-
// Implement ByReference Ctor. This wraps the assignment of the ref into a byref-like field
// in a value type. The canonical example of this is Span. In effect this is just a
// substitution. The parameter byref will be assigned into the newly allocated object.
@@ -4318,6 +4181,33 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
break;
}
+ case NI_System_RuntimeTypeHandle_GetValueInternal:
+ {
+ GenTree* op1 = impStackTop(0).val;
+ if (op1->gtOper == GT_CALL && (op1->AsCall()->gtCallType == CT_HELPER) &&
+ gtIsTypeHandleToRuntimeTypeHandleHelper(op1->AsCall()))
+ {
+ // Old tree
+ // Helper-RuntimeTypeHandle -> TreeToGetNativeTypeHandle
+ //
+ // New tree
+ // TreeToGetNativeTypeHandle
+
+ // Remove call to helper and return the native TypeHandle pointer that was the parameter
+ // to that helper.
+
+ op1 = impPopStack().val;
+
+ // Get native TypeHandle argument to old helper
+ GenTreeCall::Use* arg = op1->AsCall()->gtCallArgs;
+ assert(arg->GetNext() == nullptr);
+ op1 = arg->GetNode();
+ retNode = op1;
+ }
+ // Call the regular function.
+ break;
+ }
+
case NI_System_Type_GetTypeFromHandle:
{
GenTree* op1 = impStackTop(0).val;
@@ -4678,6 +4568,103 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
break;
}
+ case NI_System_Object_GetType:
+ {
+ JITDUMP("\n impIntrinsic: call to Object.GetType\n");
+ GenTree* op1 = impStackTop(0).val;
+
+ // If we're calling GetType on a boxed value, just get the type directly.
+ if (op1->IsBoxedValue())
+ {
+ JITDUMP("Attempting to optimize box(...).getType() to direct type construction\n");
+
+ // Try and clean up the box. Obtain the handle we
+ // were going to pass to the newobj.
+ GenTree* boxTypeHandle = gtTryRemoveBoxUpstreamEffects(op1, BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE);
+
+ if (boxTypeHandle != nullptr)
+ {
+ // Note we don't need to play the TYP_STRUCT games here like
+ // do for LDTOKEN since the return value of this operator is Type,
+ // not RuntimeTypeHandle.
+ impPopStack();
+ GenTreeCall::Use* helperArgs = gtNewCallArgs(boxTypeHandle);
+ GenTree* runtimeType =
+ gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
+ retNode = runtimeType;
+ }
+ }
+
+ // If we have a constrained callvirt with a "box this" transform
+ // we know we have a value class and hence an exact type.
+ //
+ // If so, instead of boxing and then extracting the type, just
+ // construct the type directly.
+ if ((retNode == nullptr) && (pConstrainedResolvedToken != nullptr) &&
+ (constraintCallThisTransform == CORINFO_BOX_THIS))
+ {
+ // Ensure this is one of the is simple box cases (in particular, rule out nullables).
+ const CorInfoHelpFunc boxHelper = info.compCompHnd->getBoxHelper(pConstrainedResolvedToken->hClass);
+ const bool isSafeToOptimize = (boxHelper == CORINFO_HELP_BOX);
+
+ if (isSafeToOptimize)
+ {
+ JITDUMP("Optimizing constrained box-this obj.getType() to direct type construction\n");
+ impPopStack();
+ GenTree* typeHandleOp =
+ impTokenToHandle(pConstrainedResolvedToken, nullptr, true /* mustRestoreHandle */);
+ if (typeHandleOp == nullptr)
+ {
+ assert(compDonotInline());
+ return nullptr;
+ }
+ GenTreeCall::Use* helperArgs = gtNewCallArgs(typeHandleOp);
+ GenTree* runtimeType =
+ gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
+ retNode = runtimeType;
+ }
+ }
+
+#ifdef DEBUG
+ if (retNode != nullptr)
+ {
+ JITDUMP("Optimized result for call to GetType is\n");
+ if (verbose)
+ {
+ gtDispTree(retNode);
+ }
+ }
+#endif
+
+ // Else expand as an intrinsic, unless the call is constrained,
+ // in which case we defer expansion to allow impImportCall do the
+ // special constraint processing.
+ if ((retNode == nullptr) && (pConstrainedResolvedToken == nullptr))
+ {
+ JITDUMP("Expanding as special intrinsic\n");
+ impPopStack();
+ op1 = new (this, GT_INTRINSIC)
+ GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, ni, method);
+
+ // Set the CALL flag to indicate that the operator is implemented by a call.
+ // Set also the EXCEPTION flag because the native implementation of
+ // NI_System_Object_GetType intrinsic can throw NullReferenceException.
+ op1->gtFlags |= (GTF_CALL | GTF_EXCEPT);
+ retNode = op1;
+ // Might be further optimizable, so arrange to leave a mark behind
+ isSpecial = true;
+ }
+
+ if (retNode == nullptr)
+ {
+ JITDUMP("Leaving as normal call\n");
+ // Might be further optimizable, so arrange to leave a mark behind
+ isSpecial = true;
+ }
+
+ break;
+ }
+
case NI_System_Array_GetLength:
case NI_System_Array_GetLowerBound:
case NI_System_Array_GetUpperBound:
@@ -5206,6 +5193,17 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
result = NI_System_Object_MemberwiseClone;
}
+ else if (strcmp(methodName, "GetType") == 0)
+ {
+ result = NI_System_Object_GetType;
+ }
+ }
+ else if (strcmp(className, "RuntimeTypeHandle") == 0)
+ {
+ if (strcmp(methodName, "GetValueInternal") == 0)
+ {
+ result = NI_System_RuntimeTypeHandle_GetValueInternal;
+ }
}
else if (strcmp(className, "Type") == 0)
{
@@ -5420,6 +5418,20 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
}
}
}
+ else if (strcmp(namespaceName, "System.StubHelpers") == 0)
+ {
+ if (strcmp(className, "StubHelpers") == 0)
+ {
+ if (strcmp(methodName, "GetStubContext") == 0)
+ {
+ result = NI_System_StubHelpers_GetStubContext;
+ }
+ else if (strcmp(methodName, "NextCallReturnAddress") == 0)
+ {
+ result = NI_System_StubHelpers_NextCallReturnAddress;
+ }
+ }
+ }
if (result == NI_Illegal)
{
@@ -8279,15 +8291,23 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
void** pFldAddr = nullptr;
void* fldAddr = info.compCompHnd->getFieldAddress(pResolvedToken->hField, (void**)&pFldAddr);
- // We should always be able to access this static's address directly
- //
+ // We should always be able to access this static's address directly.
assert(pFldAddr == nullptr);
+ GenTreeFlags handleKind;
+ if ((pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP) != 0)
+ {
+ handleKind = GTF_ICON_STATIC_BOX_PTR;
+ }
+ else
+ {
+ handleKind = GTF_ICON_STATIC_HDL;
+ }
+
FieldSeqNode* fldSeq = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField);
- /* Create the data member node */
- op1 = gtNewIconHandleNode(pFldAddr == nullptr ? (size_t)fldAddr : (size_t)pFldAddr, GTF_ICON_STATIC_HDL,
- fldSeq);
+ // Create the address node.
+ op1 = gtNewIconHandleNode((size_t)fldAddr, handleKind, fldSeq);
#ifdef DEBUG
op1->AsIntCon()->gtTargetHandle = op1->AsIntCon()->gtIconVal;
#endif
@@ -8338,6 +8358,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
if (pFieldInfo->fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP)
{
op1 = gtNewOperNode(GT_IND, TYP_REF, op1);
+ op1->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL);
FieldSeqNode* fldSeq = GetFieldSeqStore()->CreateSingleton(FieldSeqStore::FirstElemPseudoField);
@@ -8761,6 +8782,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
else // (opcode != CEE_CALLI)
{
CorInfoIntrinsics intrinsicID = CORINFO_INTRINSIC_Count;
+ NamedIntrinsic ni = NI_Illegal;
// Passing CORINFO_CALLINFO_ALLOWINSTPARAM indicates that this JIT is prepared to
// supply the instantiation parameters necessary to make direct calls to underlying
@@ -8848,7 +8870,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
const bool isTailCall = canTailCall && (tailCallFlags != 0);
call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken->token, isReadonlyCall,
- isTailCall, pConstrainedResolvedToken, callInfo->thisTransform, &intrinsicID,
+ isTailCall, pConstrainedResolvedToken, callInfo->thisTransform, &intrinsicID, &ni,
&isSpecialIntrinsic);
if (compDonotInline())
@@ -9076,7 +9098,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
// TODO-CQ: JIT64 does not introduce the null check for many more helper calls
// and intrinsics.
if (callInfo->nullInstanceCheck &&
- !((mflags & CORINFO_FLG_INTRINSIC) != 0 && (intrinsicID == CORINFO_INTRINSIC_Object_GetType)))
+ !((mflags & CORINFO_FLG_INTRINSIC) != 0 && (ni == NI_System_Object_GetType)))
{
call->gtFlags |= GTF_CALL_NULLCHECK;
}
@@ -18547,7 +18569,7 @@ void Compiler::impImportBlock(BasicBlock* block)
are spilling to the temps already used by a previous block),
we need to spill addStmt */
- if (addStmt != nullptr && !newTemps && gtHasRef(addStmt->GetRootNode(), tempNum, false))
+ if (addStmt != nullptr && !newTemps && gtHasRef(addStmt->GetRootNode(), tempNum))
{
GenTree* addTree = addStmt->GetRootNode();
@@ -18558,7 +18580,7 @@ void Compiler::impImportBlock(BasicBlock* block)
var_types type = genActualType(relOp->AsOp()->gtOp1->TypeGet());
- if (gtHasRef(relOp->AsOp()->gtOp1, tempNum, false))
+ if (gtHasRef(relOp->AsOp()->gtOp1, tempNum))
{
unsigned temp = lvaGrabTemp(true DEBUGARG("spill addStmt JTRUE ref Op1"));
impAssignTempGen(temp, relOp->AsOp()->gtOp1, level);
@@ -18566,7 +18588,7 @@ void Compiler::impImportBlock(BasicBlock* block)
relOp->AsOp()->gtOp1 = gtNewLclvNode(temp, type);
}
- if (gtHasRef(relOp->AsOp()->gtOp2, tempNum, false))
+ if (gtHasRef(relOp->AsOp()->gtOp2, tempNum))
{
unsigned temp = lvaGrabTemp(true DEBUGARG("spill addStmt JTRUE ref Op2"));
impAssignTempGen(temp, relOp->AsOp()->gtOp2, level);
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index 06211a597c8ed6..5f9fa62008b304 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -231,6 +231,8 @@ CONFIG_INTEGER(JitDumpFgConstrained, W("JitDumpFgConstrained"), 1) // 0 == don't
// linear layout
CONFIG_INTEGER(JitDumpFgBlockID, W("JitDumpFgBlockID"), 0) // 0 == display block with bbNum; 1 == display with both
// bbNum and bbID
+CONFIG_INTEGER(JitDumpFgBlockFlags, W("JitDumpFgBlockFlags"), 0) // 0 == don't display block flags; 1 == display flags
+CONFIG_INTEGER(JitDumpFgLoopFlags, W("JitDumpFgLoopFlags"), 0) // 0 == don't display loop flags; 1 == display flags
CONFIG_STRING(JitDumpPreciseDebugInfoFile, W("JitDumpPreciseDebugInfoFile"))
CONFIG_INTEGER(JitDisasmWithDebugInfo, W("JitDisasmWithDebugInfo"), 0)
diff --git a/src/coreclr/jit/jiteh.cpp b/src/coreclr/jit/jiteh.cpp
index c0fd2bf9581ce3..10e7652a6caa0c 100644
--- a/src/coreclr/jit/jiteh.cpp
+++ b/src/coreclr/jit/jiteh.cpp
@@ -4433,8 +4433,8 @@ void Compiler::fgExtendEHRegionBefore(BasicBlock* block)
bPrev->bbRefs++;
// If this is a handler for a filter, the last block of the filter will end with
- // a BBJ_EJFILTERRET block that has a bbJumpDest that jumps to the first block of
- // it's handler. So we need to update it to keep things in sync.
+ // a BBJ_EHFILTERRET block that has a bbJumpDest that jumps to the first block of
+ // its handler. So we need to update it to keep things in sync.
//
if (HBtab->HasFilter())
{
diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp
index a1c71f932f5a65..09f42b6e6f6659 100644
--- a/src/coreclr/jit/loopcloning.cpp
+++ b/src/coreclr/jit/loopcloning.cpp
@@ -1604,7 +1604,7 @@ bool Compiler::optIsLoopClonable(unsigned loopInd)
if (end->bbJumpDest != beg)
{
- JITDUMP("Loop cloning: rejecting loop " FMT_LP ". Branch at loop 'end' not looping to 'begin'.\n", loopInd);
+ JITDUMP("Loop cloning: rejecting loop " FMT_LP ". Branch at loop 'bottom' not looping to 'top'.\n", loopInd);
return false;
}
diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp
index 1c9febeb131440..2467a00accdaa7 100644
--- a/src/coreclr/jit/lower.cpp
+++ b/src/coreclr/jit/lower.cpp
@@ -1257,7 +1257,12 @@ GenTree* Lowering::NewPutArg(GenTreeCall* call, GenTree* arg, fgArgTabEntry* inf
}
else if (!arg->OperIs(GT_FIELD_LIST))
{
+#ifdef TARGET_ARM
+ assert((info->GetStackSlotsNumber() == 1) ||
+ ((arg->TypeGet() == TYP_DOUBLE) && (info->GetStackSlotsNumber() == 2)));
+#else
assert(varTypeIsSIMD(arg) || (info->GetStackSlotsNumber() == 1));
+#endif
}
}
#endif // FEATURE_PUT_STRUCT_ARG_STK
diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp
index ca169600e83f83..4705ee6798595e 100644
--- a/src/coreclr/jit/lsraxarch.cpp
+++ b/src/coreclr/jit/lsraxarch.cpp
@@ -2305,6 +2305,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
// Intrinsics with CopyUpperBits semantics must have op1 as target
assert(containedOpNum != 1 || !copiesUpperBits);
+ // We need to keep this in sync with hwintrinsiccodegenxarch.cpp
+ // Ideally we'd actually swap the operands here and simplify codegen
+ // but its a bit more complicated to do so for many operands as well
+ // as being complicated to tell codegen how to pick the right instruction
+
if (containedOpNum == 1)
{
// https://github.com/dotnet/runtime/issues/62215
@@ -2316,7 +2321,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
if (resultOpNum == 2)
{
// op2 = ([op1] * op2) + op3
- std::swap(emitOp2, emitOp3);
+ std::swap(emitOp1, emitOp2);
}
}
else if (containedOpNum == 3)
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index f8019ed88eec81..288f7c16f4d9b6 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -6272,13 +6272,25 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
// The address is not directly addressible, so force it into a
// constant, so we handle it properly
- GenTree* addr = gtNewIconHandleNode((size_t)fldAddr, GTF_ICON_STATIC_HDL);
- addr->gtType = TYP_I_IMPL;
- FieldSeqNode* fieldSeq =
- fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
- addr->AsIntCon()->gtFieldSeq = fieldSeq;
- // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
- if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ bool isBoxedStatic = gtIsStaticFieldPtrToBoxedStruct(tree->TypeGet(), symHnd);
+ GenTreeFlags handleKind = GTF_EMPTY;
+ if (isBoxedStatic)
+ {
+ handleKind = GTF_ICON_STATIC_BOX_PTR;
+ }
+ else if (isStaticReadOnlyInited)
+ {
+ handleKind = GTF_ICON_CONST_PTR;
+ }
+ else
+ {
+ handleKind = GTF_ICON_STATIC_HDL;
+ }
+ FieldSeqNode* fieldSeq = GetFieldSeqStore()->CreateSingleton(symHnd);
+ GenTree* addr = gtNewIconHandleNode((size_t)fldAddr, handleKind, fieldSeq);
+
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS, if we need to.
+ if (((tree->gtFlags & GTF_FLD_INITCLASS) != 0) && !isStaticReadOnlyInited)
{
tree->gtFlags &= ~GTF_FLD_INITCLASS;
addr->gtFlags |= GTF_ICON_INITCLASS;
@@ -6287,14 +6299,18 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
tree->SetOper(GT_IND);
tree->AsOp()->gtOp1 = addr;
- if (isStaticReadOnlyInited)
+ if (isBoxedStatic)
+ {
+ // The box for the static cannot be null, and is logically invariant, since it
+ // represents (a base for) the static's address.
+ tree->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL);
+ }
+ else if (isStaticReadOnlyInited)
{
JITDUMP("Marking initialized static read-only field '%s' as invariant.\n", eeGetFieldName(symHnd));
// Static readonly field is not null at this point (see getStaticFieldCurrentClass impl).
tree->gtFlags |= (GTF_IND_INVARIANT | GTF_IND_NONFAULTING | GTF_IND_NONNULL);
- tree->gtFlags &= ~GTF_ICON_INITCLASS;
- addr->gtFlags = GTF_ICON_CONST_PTR;
}
return fgMorphSmpOp(tree);
@@ -9555,17 +9571,23 @@ GenTree* Compiler::fgMorphLeaf(GenTree* tree)
}
else if (tree->gtOper == GT_FTN_ADDR)
{
+ GenTreeFptrVal* fptrValTree = tree->AsFptrVal();
+
+ // A function pointer address is being used. Let the VM know if this is the
+ // target of a Delegate or a raw function pointer.
+ bool isUnsafeFunctionPointer = !fptrValTree->gtFptrDelegateTarget;
+
CORINFO_CONST_LOOKUP addrInfo;
#ifdef FEATURE_READYTORUN
- if (tree->AsFptrVal()->gtEntryPoint.addr != nullptr)
+ if (fptrValTree->gtEntryPoint.addr != nullptr)
{
- addrInfo = tree->AsFptrVal()->gtEntryPoint;
+ addrInfo = fptrValTree->gtEntryPoint;
}
else
#endif
{
- info.compCompHnd->getFunctionFixedEntryPoint(tree->AsFptrVal()->gtFptrMethod, &addrInfo);
+ info.compCompHnd->getFunctionFixedEntryPoint(fptrValTree->gtFptrMethod, isUnsafeFunctionPointer, &addrInfo);
}
GenTree* indNode = nullptr;
@@ -11447,6 +11469,37 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
{
return fgMorphTree(optimizedTree);
}
+
+ // Pattern-matching optimization:
+ // (a % c) ==/!= 0
+ // for power-of-2 constant `c`
+ // =>
+ // a & (c - 1) ==/!= 0
+ // For integer `a`, even if negative.
+ if (opts.OptimizationEnabled() && !optValnumCSE_phase)
+ {
+ assert(tree->OperIs(GT_EQ, GT_NE));
+ if (op1->OperIs(GT_MOD) && varTypeIsIntegral(op1) && op2->IsIntegralConst(0))
+ {
+ GenTree* op1op2 = op1->AsOp()->gtOp2;
+ if (op1op2->IsCnsIntOrI())
+ {
+ const ssize_t modValue = op1op2->AsIntCon()->IconValue();
+ if (isPow2(modValue))
+ {
+ JITDUMP("\nTransforming:\n");
+ DISPTREE(tree);
+
+ op1->SetOper(GT_AND); // Change % => &
+ op1op2->AsIntConCommon()->SetIconValue(modValue - 1); // Change c => c - 1
+ fgUpdateConstTreeValueNumber(op1op2);
+
+ JITDUMP("\ninto:\n");
+ DISPTREE(tree);
+ }
+ }
+ }
+ }
}
FALLTHROUGH;
@@ -13355,30 +13408,6 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp)
GenTree* op1 = cmp->gtGetOp1();
GenTreeIntConCommon* op2 = cmp->gtGetOp2()->AsIntConCommon();
- // Pattern-matching optimization:
- // (a % c) ==/!= 0
- // for power-of-2 constant `c`
- // =>
- // a & (c - 1) ==/!= 0
- // For integer `a`, even if negative.
- if (opts.OptimizationEnabled())
- {
- if (op1->OperIs(GT_MOD) && varTypeIsIntegral(op1) && op2->IsIntegralConst(0))
- {
- GenTree* op1op2 = op1->AsOp()->gtOp2;
- if (op1op2->IsCnsIntOrI())
- {
- ssize_t modValue = op1op2->AsIntCon()->IconValue();
- if (isPow2(modValue))
- {
- op1->SetOper(GT_AND); // Change % => &
- op1op2->AsIntConCommon()->SetIconValue(modValue - 1); // Change c => c - 1
- fgUpdateConstTreeValueNumber(op1op2);
- }
- }
- }
- }
-
// Check for "(expr +/- icon1) ==/!= (non-zero-icon2)".
if (op2->IsCnsIntOrI() && (op2->IconValue() != 0))
{
diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h
index 62ebb80c089994..5d07e88b576ae7 100644
--- a/src/coreclr/jit/namedintrinsiclist.h
+++ b/src/coreclr/jit/namedintrinsiclist.h
@@ -60,6 +60,10 @@ enum NamedIntrinsic : unsigned short
NI_System_Array_GetLowerBound,
NI_System_Array_GetUpperBound,
NI_System_Object_MemberwiseClone,
+ NI_System_Object_GetType,
+ NI_System_RuntimeTypeHandle_GetValueInternal,
+ NI_System_StubHelpers_GetStubContext,
+ NI_System_StubHelpers_NextCallReturnAddress,
NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan,
NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray,
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index 39d2328c2e8d62..43e9616b2192fc 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -413,19 +413,42 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar
continue;
}
- if (block == loop.lpEntry || block == loop.lpBottom)
- {
- loop.lpFlags |= LPFLG_REMOVED;
- continue;
- }
+ // Avoid printing to the JitDump unless we're actually going to change something.
+ // If we call reportBefore, then we're going to change the loop table, and we should print the
+ // `reportAfter` info as well. Only print the `reportBefore` info once, if multiple changes to
+ // the table are made.
+ INDEBUG(bool reportedBefore = false);
+ auto reportBefore = [&]() {
#ifdef DEBUG
- if (verbose)
+ if (verbose && !reportedBefore)
+ {
+ printf("optUpdateLoopsBeforeRemoveBlock " FMT_BB " Before: ", block->bbNum);
+ optPrintLoopInfo(loopNum);
+ printf("\n");
+ reportedBefore = true;
+ }
+#endif // DEBUG
+ };
+
+ auto reportAfter = [&]() {
+#ifdef DEBUG
+ if (verbose && reportedBefore)
+ {
+ printf("optUpdateLoopsBeforeRemoveBlock " FMT_BB " After: ", block->bbNum);
+ optPrintLoopInfo(loopNum);
+ printf("\n");
+ }
+#endif // DEBUG
+ };
+
+ if (block == loop.lpEntry || block == loop.lpBottom)
{
- printf("\nUpdateLoopsBeforeRemoveBlock Before: ");
- optPrintLoopInfo(loopNum);
+ reportBefore();
+ optMarkLoopRemoved(loopNum);
+ reportAfter();
+ continue;
}
-#endif
/* If the loop is still in the table
* any block in the loop must be reachable !!! */
@@ -435,6 +458,7 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar
if (loop.lpExit == block)
{
+ reportBefore();
loop.lpExit = nullptr;
loop.lpFlags &= ~LPFLG_ONE_EXIT;
}
@@ -537,23 +561,18 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar
if (removeLoop)
{
- loop.lpFlags |= LPFLG_REMOVED;
+ reportBefore();
+ optMarkLoopRemoved(loopNum);
}
}
else if (loop.lpHead == block)
{
+ reportBefore();
/* The loop has a new head - Just update the loop table */
loop.lpHead = block->bbPrev;
}
-#ifdef DEBUG
- if (verbose)
- {
- printf("\nUpdateLoopsBeforeRemoveBlock After: ");
- optPrintLoopInfo(loopNum);
- printf("\n");
- }
-#endif
+ reportAfter();
}
if ((skipUnmarkLoop == false) && //
@@ -575,43 +594,156 @@ void Compiler::optUpdateLoopsBeforeRemoveBlock(BasicBlock* block, bool skipUnmar
* Print loop info in an uniform way.
*/
-void Compiler::optPrintLoopInfo(unsigned loopInd,
- BasicBlock* lpHead,
- BasicBlock* lpTop,
- BasicBlock* lpEntry,
- BasicBlock* lpBottom,
- unsigned char lpExitCnt,
- BasicBlock* lpExit,
- unsigned parentLoop) const
+void Compiler::optPrintLoopInfo(const LoopDsc* loop, bool printVerbose /* = false */)
{
- printf(FMT_LP ", from " FMT_BB " to " FMT_BB " (Head=" FMT_BB ", Entry=" FMT_BB ", ExitCnt=%d", loopInd,
- lpTop->bbNum, lpBottom->bbNum, lpHead->bbNum, lpEntry->bbNum, lpExitCnt);
+ assert(optLoopTable != nullptr);
+ assert((&optLoopTable[0] <= loop) && (loop < &optLoopTable[optLoopCount]));
+
+ unsigned lnum = (unsigned)(loop - optLoopTable);
+ assert(lnum < optLoopCount);
+ assert(&optLoopTable[lnum] == loop);
- if (lpExitCnt == 1)
+ if (loop->lpFlags & LPFLG_REMOVED)
{
- printf(" at " FMT_BB, lpExit->bbNum);
+ // If a loop has been removed, it might be dangerous to print its fields (e.g., loop unrolling
+ // nulls out the lpHead field).
+ printf(FMT_LP " REMOVED", lnum);
+ return;
}
- if (parentLoop != BasicBlock::NOT_IN_LOOP)
+ printf(FMT_LP ", from " FMT_BB " to " FMT_BB " (Head=" FMT_BB ", Entry=" FMT_BB, lnum, loop->lpTop->bbNum,
+ loop->lpBottom->bbNum, loop->lpHead->bbNum, loop->lpEntry->bbNum);
+
+ if (loop->lpExitCnt == 1)
{
- printf(", parent loop = " FMT_LP, parentLoop);
+ printf(", Exit=" FMT_BB, loop->lpExit->bbNum);
+ }
+ else
+ {
+ printf(", ExitCnt=%d", loop->lpExitCnt);
+ }
+
+ if (loop->lpParent != BasicBlock::NOT_IN_LOOP)
+ {
+ printf(", parent=" FMT_LP, loop->lpParent);
}
printf(")");
-}
-/*****************************************************************************
- *
- * Print loop information given the index of the loop in the loop table.
- */
+ if (printVerbose)
+ {
+ if (loop->lpChild != BasicBlock::NOT_IN_LOOP)
+ {
+ printf(", child loop = " FMT_LP, loop->lpChild);
+ }
+ if (loop->lpSibling != BasicBlock::NOT_IN_LOOP)
+ {
+ printf(", sibling loop = " FMT_LP, loop->lpSibling);
+ }
+
+ // If an iterator loop print the iterator and the initialization.
+ if (loop->lpFlags & LPFLG_ITER)
+ {
+ printf(" [over V%02u", loop->lpIterVar());
+ printf(" (");
+ printf(GenTree::OpName(loop->lpIterOper()));
+ printf(" %d)", loop->lpIterConst());
+
+ if (loop->lpFlags & LPFLG_CONST_INIT)
+ {
+ printf(" from %d", loop->lpConstInit);
+ }
+ if (loop->lpFlags & LPFLG_VAR_INIT)
+ {
+ printf(" from V%02u", loop->lpVarInit);
+ }
+
+ // If a simple test condition print operator and the limits */
+ printf(" %s", GenTree::OpName(loop->lpTestOper()));
+
+ if (loop->lpFlags & LPFLG_CONST_LIMIT)
+ {
+ printf(" %d", loop->lpConstLimit());
+ if (loop->lpFlags & LPFLG_SIMD_LIMIT)
+ {
+ printf(" (simd)");
+ }
+ }
+ if (loop->lpFlags & LPFLG_VAR_LIMIT)
+ {
+ printf(" V%02u", loop->lpVarLimit());
+ }
+ if (loop->lpFlags & LPFLG_ARRLEN_LIMIT)
+ {
+ ArrIndex* index = new (getAllocator(CMK_DebugOnly)) ArrIndex(getAllocator(CMK_DebugOnly));
+ if (loop->lpArrLenLimit(this, index))
+ {
+ printf(" ");
+ index->Print();
+ printf(".Length");
+ }
+ else
+ {
+ printf(" ???.Length");
+ }
+ }
+
+ printf("]");
+ }
+
+ // Print the flags
+
+ if (loop->lpContainsCall)
+ {
+ printf(" call");
+ }
+ if (loop->lpFlags & LPFLG_HAS_PREHEAD)
+ {
+ printf(" prehead");
+ }
+ if (loop->lpFlags & LPFLG_DONT_UNROLL)
+ {
+ printf(" !unroll");
+ }
+ if (loop->lpFlags & LPFLG_ASGVARS_YES)
+ {
+ printf(" avyes");
+ }
+ if (loop->lpFlags & LPFLG_ASGVARS_INC)
+ {
+ printf(" avinc");
+ }
+ }
+}
-void Compiler::optPrintLoopInfo(unsigned lnum) const
+void Compiler::optPrintLoopInfo(unsigned lnum, bool printVerbose /* = false */)
{
assert(lnum < optLoopCount);
- const LoopDsc* ldsc = &optLoopTable[lnum];
+ const LoopDsc& loop = optLoopTable[lnum];
+ optPrintLoopInfo(&loop, printVerbose);
+}
+
+//------------------------------------------------------------------------
+// optPrintLoopTable: Print the loop table
+//
+void Compiler::optPrintLoopTable()
+{
+ printf("\n*************** Natural loop table\n");
+
+ if (optLoopCount == 0)
+ {
+ printf("No loops\n");
+ }
+ else
+ {
+ for (unsigned loopInd = 0; loopInd < optLoopCount; loopInd++)
+ {
+ optPrintLoopInfo(loopInd, /* verbose */ true);
+ printf("\n");
+ }
+ }
- optPrintLoopInfo(lnum, ldsc->lpHead, ldsc->lpTop, ldsc->lpEntry, ldsc->lpBottom, ldsc->lpExitCnt, ldsc->lpExit,
- ldsc->lpParent);
+ printf("\n");
}
#endif // DEBUG
@@ -1111,6 +1243,7 @@ bool Compiler::optRecordLoop(
{
optLoopTable[loopInd].lpLoopHasMemoryHavoc[memoryKind] = false;
}
+ optLoopTable[loopInd].lpContainsCall = false;
optLoopTable[loopInd].lpFieldsModified = nullptr;
optLoopTable[loopInd].lpArrayElemTypesModified = nullptr;
@@ -1229,63 +1362,23 @@ bool Compiler::optRecordLoop(
}
DONE_LOOP:
- DBEXEC(verbose, optPrintLoopRecording(loopInd));
+
+ bool loopInsertedAtEnd = (loopInd == optLoopCount);
optLoopCount++;
- return true;
-}
#ifdef DEBUG
-//------------------------------------------------------------------------
-// optPrintLoopRecording: Print a recording of the loop.
-//
-// Arguments:
-// loopInd - loop index.
-//
-void Compiler::optPrintLoopRecording(unsigned loopInd) const
-{
- const LoopDsc& loop = optLoopTable[loopInd];
-
- printf("Recorded loop %s", (loopInd != optLoopCount ? "(extended) " : ""));
- optPrintLoopInfo(optLoopCount, // Not necessarily the loop index, but the number of loops that have been added.
- loop.lpHead, loop.lpTop, loop.lpEntry, loop.lpBottom, loop.lpExitCnt, loop.lpExit);
-
- // If an iterator loop print the iterator and the initialization.
- if (loop.lpFlags & LPFLG_ITER)
+ if (verbose)
{
- printf(" [over V%02u", loop.lpIterVar());
- printf(" (");
- printf(GenTree::OpName(loop.lpIterOper()));
- printf(" ");
- printf("%d )", loop.lpIterConst());
-
- if (loop.lpFlags & LPFLG_CONST_INIT)
- {
- printf(" from %d", loop.lpConstInit);
- }
- if (loop.lpFlags & LPFLG_VAR_INIT)
- {
- printf(" from V%02u", loop.lpVarInit);
- }
-
- // If a simple test condition print operator and the limits */
- printf(GenTree::OpName(loop.lpTestOper()));
-
- if (loop.lpFlags & LPFLG_CONST_LIMIT)
- {
- printf("%d ", loop.lpConstLimit());
- }
-
- if (loop.lpFlags & LPFLG_VAR_LIMIT)
- {
- printf("V%02u ", loop.lpVarLimit());
- }
-
- printf("]");
+ printf("Recorded loop %s", loopInsertedAtEnd ? "" : "(extended) ");
+ optPrintLoopInfo(loopInd, /* verbose */ true);
+ printf("\n");
}
+#endif // DEBUG
- printf("\n");
+ return true;
}
+#ifdef DEBUG
void Compiler::optCheckPreds()
{
for (BasicBlock* const block : Blocks())
@@ -2476,12 +2569,7 @@ void Compiler::optFindNaturalLoops()
#ifdef DEBUG
if (verbose && (optLoopCount > 0))
{
- printf("\nFinal natural loop table:\n");
- for (unsigned loopInd = 0; loopInd < optLoopCount; loopInd++)
- {
- optPrintLoopInfo(loopInd);
- printf("\n");
- }
+ optPrintLoopTable();
}
#endif // DEBUG
}
@@ -2909,7 +2997,7 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd)
// Notes:
// A loop contains itself.
//
-bool Compiler::optLoopContains(unsigned l1, unsigned l2)
+bool Compiler::optLoopContains(unsigned l1, unsigned l2) const
{
assert(l1 < optLoopCount);
assert((l2 < optLoopCount) || (l2 == BasicBlock::NOT_IN_LOOP));
@@ -3501,6 +3589,8 @@ PhaseStatus Compiler::optUnrollLoops()
/* Look for loop unrolling candidates */
bool change = false;
+ INDEBUG(int unrollCount = 0); // count of loops unrolled
+ INDEBUG(int unrollFailures = 0); // count of loops attempted to be unrolled, but failed
static const unsigned ITER_LIMIT[COUNT_OPT_CODE + 1] = {
10, // BLENDED_CODE
@@ -3568,6 +3658,7 @@ PhaseStatus Compiler::optUnrollLoops()
if ((loopFlags & requiredFlags) != requiredFlags)
{
+ // Don't print to the JitDump about this common case.
continue;
}
@@ -3575,6 +3666,7 @@ PhaseStatus Compiler::optUnrollLoops()
if (loopFlags & (LPFLG_DONT_UNROLL | LPFLG_REMOVED))
{
+ // Don't print to the JitDump about this common case.
continue;
}
@@ -3605,11 +3697,13 @@ PhaseStatus Compiler::optUnrollLoops()
if (lvaTable[lvar].IsAddressExposed())
{
// If the loop iteration variable is address-exposed then bail
+ JITDUMP("Failed to unroll loop " FMT_LP ": V%02u is address exposed\n", lnum, lvar);
continue;
}
if (lvaTable[lvar].lvIsStructField)
{
// If the loop iteration variable is a promoted field from a struct then bail
+ JITDUMP("Failed to unroll loop " FMT_LP ": V%02u is a promoted struct field\n", lnum, lvar);
continue;
}
@@ -3641,6 +3735,7 @@ PhaseStatus Compiler::optUnrollLoops()
if (!optComputeLoopRep(lbeg, llim, iterInc, iterOper, iterOperType, testOper, unsTest, dupCond, &totalIter))
{
+ JITDUMP("Failed to unroll loop " FMT_LP ": not a constant iteration count\n", lnum);
continue;
}
@@ -3648,6 +3743,8 @@ PhaseStatus Compiler::optUnrollLoops()
if (totalIter > iterLimit)
{
+ JITDUMP("Failed to unroll loop " FMT_LP ": too many iterations (%d > %d) (heuristic)\n", lnum, totalIter,
+ iterLimit);
continue;
}
@@ -3668,6 +3765,7 @@ PhaseStatus Compiler::optUnrollLoops()
{
// Otherwise unroll only if limit is Vector_.Length
// (as a heuristic, not for correctness/structural reasons)
+ JITDUMP("Failed to unroll loop " FMT_LP ": constant limit isn't Vector.Length (heuristic)\n", lnum);
continue;
}
@@ -3676,6 +3774,8 @@ PhaseStatus Compiler::optUnrollLoops()
// Don't unroll loops we don't understand.
if (incr->gtOper != GT_ASG)
{
+ JITDUMP("Failed to unroll loop " FMT_LP ": unknown increment op (%s)\n", lnum,
+ GenTree::OpName(incr->gtOper));
continue;
}
incr = incr->AsOp()->gtOp2;
@@ -3717,6 +3817,7 @@ PhaseStatus Compiler::optUnrollLoops()
if (block->bbTryIndex != tryIndex)
{
// Unrolling would require cloning EH regions
+ JITDUMP("Failed to unroll loop " FMT_LP ": EH constraint\n", lnum);
goto DONE_LOOP;
}
@@ -3741,6 +3842,7 @@ PhaseStatus Compiler::optUnrollLoops()
if (fgReturnCount + loopRetCount * (totalIter - 1) > SET_EPILOGCNT_MAX)
{
// Jit32 GC encoder can't report more than SET_EPILOGCNT_MAX epilogs.
+ JITDUMP("Failed to unroll loop " FMT_LP ": GC encoder max epilog constraint\n", lnum);
goto DONE_LOOP;
}
#endif // !JIT32_GCENCODER
@@ -3756,6 +3858,8 @@ PhaseStatus Compiler::optUnrollLoops()
if (unrollCostSz.IsOverflow() || (unrollCostSz.Value() > unrollLimitSz))
{
+ JITDUMP("Failed to unroll loop " FMT_LP ": size constraint (%d > %d) (heuristic)\n", lnum,
+ unrollCostSz.Value(), unrollLimitSz);
goto DONE_LOOP;
}
@@ -3765,11 +3869,8 @@ PhaseStatus Compiler::optUnrollLoops()
#ifdef DEBUG
if (verbose)
{
- printf("\nUnrolling loop " FMT_BB, head->bbNext->bbNum);
- if (head->bbNext->bbNum != bottom->bbNum)
- {
- printf(".." FMT_BB, bottom->bbNum);
- }
+ printf("\nUnrolling loop ");
+ optPrintLoopInfo(&optLoopTable[lnum]);
printf(" over V%02u from %u to %u unrollCostSz = %d\n\n", lvar, lbeg, llim, unrollCostSz);
}
#endif
@@ -3807,6 +3908,9 @@ PhaseStatus Compiler::optUnrollLoops()
bottom->bbNext = oldBottomNext;
oldBottomNext->bbPrev = bottom;
optLoopTable[lnum].lpFlags |= LPFLG_DONT_UNROLL;
+ INDEBUG(++unrollFailures);
+ JITDUMP("Failed to unroll loop " FMT_LP ": block cloning failed on " FMT_BB "\n", lnum,
+ block->bbNum);
goto DONE_LOOP;
}
@@ -3941,6 +4045,8 @@ PhaseStatus Compiler::optUnrollLoops()
// Note if we created new BBJ_RETURNs
fgReturnCount += loopRetCount * (totalIter - 1);
+
+ INDEBUG(++unrollCount);
}
DONE_LOOP:;
@@ -3948,8 +4054,33 @@ PhaseStatus Compiler::optUnrollLoops()
if (change)
{
+#ifdef DEBUG
+ if (verbose)
+ {
+ printf("\nFinished unrolling %d loops", unrollCount);
+ if (unrollFailures > 0)
+ {
+ printf(", %d failures due to block cloning", unrollFailures);
+ }
+ printf("\n");
+ }
+#endif // DEBUG
+
constexpr bool computePreds = true;
fgUpdateChangedFlowGraph(computePreds);
+
+ DBEXEC(verbose, fgDispBasicBlocks());
+ }
+ else
+ {
+#ifdef DEBUG
+ assert(unrollCount == 0);
+
+ if (unrollFailures > 0)
+ {
+ printf("\nFinished loop unrolling, %d failures due to block cloning\n", unrollFailures);
+ }
+#endif // DEBUG
}
#ifdef DEBUG
@@ -4629,6 +4760,8 @@ void Compiler::optMarkLoopHeads()
{
printf("*************** In optMarkLoopHeads()\n");
}
+
+ int loopHeadsMarked = 0;
#endif
bool hasLoops = false;
@@ -4653,12 +4786,14 @@ void Compiler::optMarkLoopHeads()
{
hasLoops = true;
block->bbFlags |= BBF_LOOP_HEAD;
+ INDEBUG(++loopHeadsMarked);
break; // No need to look at more `block` predecessors
}
}
}
}
+ JITDUMP("%d loop heads marked\n", loopHeadsMarked);
fgHasLoops = hasLoops;
}
@@ -5510,7 +5645,8 @@ void Compiler::optPerformHoistExpr(GenTree* origExpr, BasicBlock* exprBb, unsign
{
printf("\nHoisting a copy of ");
printTreeID(origExpr);
- printf(" into PreHeader for loop " FMT_LP " <" FMT_BB ".." FMT_BB ">:\n", lnum, optLoopTable[lnum].lpTop->bbNum,
+ 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);
gtDispTree(origExpr);
printf("\n");
@@ -5708,7 +5844,8 @@ void Compiler::optHoistLoopCode()
printf("\n*************** In optHoistLoopCode()\n");
printf("Blocks/Trees before phase\n");
fgDispBasicBlocks(true);
- printf("");
+ fgDispHandlerTab();
+ optPrintLoopTable();
}
#endif
@@ -5847,7 +5984,7 @@ void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt)
// We must have a do-while loop
if ((pLoopDsc->lpFlags & LPFLG_DO_WHILE) == 0)
{
- JITDUMP(" ... not hoisting " FMT_LP ": not do-while\n", lnum);
+ JITDUMP(" ... not hoisting " FMT_LP ": not top entry\n", lnum);
return;
}
@@ -5885,7 +6022,7 @@ void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt)
#ifdef DEBUG
if (verbose)
{
- printf("optHoistLoopCode for loop " FMT_LP " <" FMT_BB ".." FMT_BB ">:\n", lnum, begn, endn);
+ printf("optHoistThisLoop for loop " FMT_LP " <" FMT_BB ".." FMT_BB ">:\n", lnum, begn, endn);
printf(" Loop body %s a call\n", pLoopDsc->lpContainsCall ? "contains" : "does not contain");
printf(" Loop has %s\n", (pLoopDsc->lpFlags & LPFLG_ONE_EXIT) ? "single exit" : "multiple exits");
}
@@ -6408,7 +6545,7 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo
m_valueStack.Reset();
}
- // Only uncondtionally executed blocks in the loop are visited (see optHoistThisLoop)
+ // Only unconditionally executed blocks in the loop are visited (see optHoistThisLoop)
// so after we're done visiting the first block we need to assume the worst, that the
// blocks that are not visisted have side effects.
m_beforeSideEffect = false;
@@ -6778,10 +6915,8 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo
BasicBlock* block = blocks->Pop();
weight_t blockWeight = block->getBBWeight(this);
- JITDUMP("\n optHoistLoopBlocks " FMT_BB " (weight=%6s) of loop " FMT_LP " <" FMT_BB ".." FMT_BB
- ">, firstBlock is %s\n",
- block->bbNum, refCntWtd2str(blockWeight), loopNum, loopDsc->lpTop->bbNum, loopDsc->lpBottom->bbNum,
- dspBool(block == loopDsc->lpEntry));
+ JITDUMP("\n optHoistLoopBlocks " FMT_BB " (weight=%6s) of loop " FMT_LP " <" FMT_BB ".." FMT_BB ">\n",
+ block->bbNum, refCntWtd2str(blockWeight), loopNum, loopDsc->lpTop->bbNum, loopDsc->lpBottom->bbNum);
if (blockWeight < (BB_UNITY_WEIGHT / 10))
{
@@ -7222,6 +7357,16 @@ void Compiler::fgCreateLoopPreHeader(unsigned lnum)
}
}
}
+
+#ifdef DEBUG
+ if (verbose)
+ {
+ JITDUMP("*************** After fgCreateLoopPreHeader for " FMT_LP "\n", lnum);
+ fgDispBasicBlocks();
+ fgDispHandlerTab();
+ optPrintLoopTable();
+ }
+#endif
}
bool Compiler::optBlockIsLoopEntry(BasicBlock* blk, unsigned* pLnum)
@@ -7290,8 +7435,8 @@ void Compiler::optComputeLoopSideEffects()
void Compiler::optComputeLoopNestSideEffects(unsigned lnum)
{
+ JITDUMP("optComputeLoopNestSideEffects for " FMT_LP "\n", lnum);
assert(optLoopTable[lnum].lpParent == BasicBlock::NOT_IN_LOOP); // Requires: lnum is outermost.
- JITDUMP("optComputeLoopSideEffects lnum is %d\n", lnum);
for (BasicBlock* const bbInLoop : optLoopTable[lnum].LoopBlocks())
{
if (!optComputeLoopSideEffectsOfBlock(bbInLoop))
@@ -9122,3 +9267,67 @@ void Compiler::optRemoveRedundantZeroInits()
block->bbFlags &= ~BBF_MARKED;
}
}
+
+#ifdef DEBUG
+
+//------------------------------------------------------------------------
+// optAnyChildNotRemoved: Recursively check the child loops of a loop to see if any of them
+// are still live (that is, not marked as LPFLG_REMOVED). This check is done when we are
+// removing a parent, just to notify that there is something odd about leaving a live child.
+//
+// Arguments:
+// loopNum - the loop number to check
+//
+bool Compiler::optAnyChildNotRemoved(unsigned loopNum)
+{
+ assert(loopNum < optLoopCount);
+
+ // Now recursively mark the children.
+ for (BasicBlock::loopNumber l = optLoopTable[loopNum].lpChild; //
+ l != BasicBlock::NOT_IN_LOOP; //
+ l = optLoopTable[l].lpSibling)
+ {
+ if ((optLoopTable[l].lpFlags & LPFLG_REMOVED) == 0)
+ {
+ return true;
+ }
+
+ if (optAnyChildNotRemoved(l))
+ {
+ return true;
+ }
+ }
+
+ // All children were removed
+ return false;
+}
+
+#endif // DEBUG
+
+//------------------------------------------------------------------------
+// optMarkLoopRemoved: Mark the specified loop as removed (some optimization, such as unrolling, has made the
+// loop no longer exist). Note that only the given loop is marked as being removed; if it has any children,
+// they are not touched (but a warning message is output to the JitDump).
+//
+// Arguments:
+// loopNum - the loop number to remove
+//
+void Compiler::optMarkLoopRemoved(unsigned loopNum)
+{
+ JITDUMP("Marking loop " FMT_LP " removed\n", loopNum);
+
+ assert(loopNum < optLoopCount);
+ LoopDsc& loop = optLoopTable[loopNum];
+ loop.lpFlags |= LPFLG_REMOVED;
+
+#ifdef DEBUG
+ if (optAnyChildNotRemoved(loopNum))
+ {
+ JITDUMP("Removed loop " FMT_LP " has one or more live children\n", loopNum);
+ }
+
+// Note: we can't call `fgDebugCheckLoopTable()` here because if there are live children, it will assert.
+// Assume the caller is going to fix up the table and `bbNatLoopNum` block annotations before the next time
+// `fgDebugCheckLoopTable()` is called.
+#endif // DEBUG
+}
diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp
index 4b957a720adc34..8590ecdd81c9f1 100644
--- a/src/coreclr/jit/rangecheck.cpp
+++ b/src/coreclr/jit/rangecheck.cpp
@@ -336,18 +336,20 @@ void RangeCheck::Widen(BasicBlock* block, GenTree* tree, Range* pRange)
bool RangeCheck::IsBinOpMonotonicallyIncreasing(GenTreeOp* binop)
{
- assert(binop->OperIs(GT_ADD));
+ assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH));
GenTree* op1 = binop->gtGetOp1();
GenTree* op2 = binop->gtGetOp2();
JITDUMP("[RangeCheck::IsBinOpMonotonicallyIncreasing] [%06d], [%06d]\n", Compiler::dspTreeID(op1),
Compiler::dspTreeID(op2));
- // Check if we have a var + const.
- if (op2->OperGet() == GT_LCL_VAR)
+
+ // Check if we have a var + const or var * const.
+ if (binop->OperIs(GT_ADD, GT_MUL) && op2->OperGet() == GT_LCL_VAR)
{
std::swap(op1, op2);
}
+
if (op1->OperGet() != GT_LCL_VAR)
{
JITDUMP("Not monotonically increasing because op1 is not lclVar.\n");
@@ -356,7 +358,8 @@ bool RangeCheck::IsBinOpMonotonicallyIncreasing(GenTreeOp* binop)
switch (op2->OperGet())
{
case GT_LCL_VAR:
- // When adding two local variables, we also must ensure that any constant is non-negative.
+ // When adding/multiplying/shifting two local variables, we also must ensure that any constant is
+ // non-negative.
return IsMonotonicallyIncreasing(op1, true) && IsMonotonicallyIncreasing(op2, true);
case GT_CNS_INT:
@@ -417,7 +420,7 @@ bool RangeCheck::IsMonotonicallyIncreasing(GenTree* expr, bool rejectNegativeCon
return (ssaDef != nullptr) &&
IsMonotonicallyIncreasing(ssaDef->GetAssignment()->gtGetOp2(), rejectNegativeConst);
}
- else if (expr->OperGet() == GT_ADD)
+ else if (expr->OperIs(GT_ADD, GT_MUL, GT_LSH))
{
return IsBinOpMonotonicallyIncreasing(expr->AsOp());
}
@@ -894,11 +897,12 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE
// Compute the range for a binary operation.
Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool monIncreasing DEBUGARG(int indent))
{
- assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD));
+ assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL));
GenTree* op1 = binop->gtGetOp1();
GenTree* op2 = binop->gtGetOp2();
+ // Special cases for binops where op2 is a constant
if (binop->OperIs(GT_AND, GT_RSH, GT_LSH, GT_UMOD))
{
if (!op2->IsIntCnsFitsInI32())
@@ -929,17 +933,21 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
}
}
- if (icon < 0)
+ if (icon >= 0)
+ {
+ Range range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, icon));
+ JITDUMP("Limit range to %s\n", range.ToString(m_pCompiler->getAllocatorDebugOnly()));
+ return range;
+ }
+ // Generalized range computation not implemented for these operators
+ else if (binop->OperIs(GT_AND, GT_UMOD, GT_RSH))
{
return Range(Limit::keUnknown);
}
- Range range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, icon));
- JITDUMP("Limit range to %s\n", range.ToString(m_pCompiler->getAllocatorDebugOnly()));
- return range;
}
// other operators are expected to be handled above.
- assert(binop->OperIs(GT_ADD));
+ assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH));
Range* op1RangeCached = nullptr;
Range op1Range = Limit(Limit::keUndef);
@@ -985,9 +993,30 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
op2Range = *op2RangeCached;
}
- Range r = RangeOps::Add(op1Range, op2Range);
- JITDUMP("BinOp add ranges %s %s = %s\n", op1Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
- op2Range.ToString(m_pCompiler->getAllocatorDebugOnly()), r.ToString(m_pCompiler->getAllocatorDebugOnly()));
+ Range r = Range(Limit::keUnknown);
+ if (binop->OperIs(GT_ADD))
+ {
+ r = RangeOps::Add(op1Range, op2Range);
+ JITDUMP("BinOp add ranges %s %s = %s\n", op1Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ op2Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ r.ToString(m_pCompiler->getAllocatorDebugOnly()));
+ }
+ else if (binop->OperIs(GT_MUL))
+ {
+ r = RangeOps::Multiply(op1Range, op2Range);
+ JITDUMP("BinOp multiply ranges %s %s = %s\n", op1Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ op2Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ r.ToString(m_pCompiler->getAllocatorDebugOnly()));
+ }
+ else if (binop->OperIs(GT_LSH))
+ {
+ // help the next step a bit, convert the LSH rhs to a multiply
+ Range convertedOp2Range = RangeOps::ConvertShiftToMultiply(op2Range);
+ r = RangeOps::Multiply(op1Range, convertedOp2Range);
+ JITDUMP("BinOp multiply ranges %s %s = %s\n", op1Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ convertedOp2Range.ToString(m_pCompiler->getAllocatorDebugOnly()),
+ r.ToString(m_pCompiler->getAllocatorDebugOnly()));
+ }
return r;
}
@@ -1077,6 +1106,24 @@ bool RangeCheck::AddOverflows(Limit& limit1, Limit& limit2)
return IntAddOverflows(max1, max2);
}
+// Check if the arithmetic overflows.
+bool RangeCheck::MultiplyOverflows(Limit& limit1, Limit& limit2)
+{
+ int max1;
+ if (!GetLimitMax(limit1, &max1))
+ {
+ return true;
+ }
+
+ int max2;
+ if (!GetLimitMax(limit2, &max2))
+ {
+ return true;
+ }
+
+ return CheckedOps::MulOverflows(max1, max2, CheckedOps::Signed);
+}
+
// Does the bin operation overflow.
bool RangeCheck::DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop)
{
@@ -1109,10 +1156,15 @@ bool RangeCheck::DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop)
JITDUMP("Checking bin op overflow %s %s\n", op1Range->ToString(m_pCompiler->getAllocatorDebugOnly()),
op2Range->ToString(m_pCompiler->getAllocatorDebugOnly()));
- if (!AddOverflows(op1Range->UpperLimit(), op2Range->UpperLimit()))
+ if (binop->OperIs(GT_ADD))
{
- return false;
+ return AddOverflows(op1Range->UpperLimit(), op2Range->UpperLimit());
}
+ else if (binop->OperIs(GT_MUL))
+ {
+ return MultiplyOverflows(op1Range->UpperLimit(), op2Range->UpperLimit());
+ }
+
return true;
}
@@ -1180,7 +1232,7 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr)
overflows = DoesVarDefOverflow(expr->AsLclVarCommon());
}
// Check if add overflows.
- else if (expr->OperGet() == GT_ADD)
+ else if (expr->OperGet() == GT_ADD || expr->OperGet() == GT_MUL)
{
overflows = DoesBinOpOverflow(block, expr->AsOp());
}
@@ -1276,7 +1328,7 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monIncreas
MergeAssertion(block, expr, &range DEBUGARG(indent + 1));
}
// compute the range for binary operation
- else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD))
+ else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL))
{
range = ComputeRangeForBinOp(block, expr->AsOp(), monIncreasing DEBUGARG(indent + 1));
}
diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h
index 751b243740c408..7161aa2d162c4e 100644
--- a/src/coreclr/jit/rangecheck.h
+++ b/src/coreclr/jit/rangecheck.h
@@ -147,6 +147,28 @@ struct Limit
return false;
}
+ bool MultiplyConstant(int i)
+ {
+ switch (type)
+ {
+ case keDependent:
+ return true;
+ case keBinOpArray:
+ case keConstant:
+ if (CheckedOps::MulOverflows(cns, i, CheckedOps::Signed))
+ {
+ return false;
+ }
+ cns *= i;
+ return true;
+ case keUndef:
+ case keUnknown:
+ // For these values of 'type', conservatively return false
+ break;
+ }
+
+ return false;
+ }
bool Equals(Limit& l)
{
@@ -250,6 +272,21 @@ struct RangeOps
}
}
+ // Given a constant limit in "l1", multiply it to l2 and mutate "l2".
+ static Limit MultiplyConstantLimit(Limit& l1, Limit& l2)
+ {
+ assert(l1.IsConstant());
+ Limit l = l2;
+ if (l.MultiplyConstant(l1.GetConstant()))
+ {
+ return l;
+ }
+ else
+ {
+ return Limit(Limit::keUnknown);
+ }
+ }
+
// Given two ranges "r1" and "r2", perform an add operation on the
// ranges.
static Range Add(Range& r1, Range& r2)
@@ -291,6 +328,47 @@ struct RangeOps
return result;
}
+ // Given two ranges "r1" and "r2", perform an multiply operation on the
+ // ranges.
+ static Range Multiply(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);
+
+ // Check lo ranges if they are dependent and not unknown.
+ if ((r1lo.IsDependent() && !r1lo.IsUnknown()) || (r2lo.IsDependent() && !r2lo.IsUnknown()))
+ {
+ result.lLimit = Limit(Limit::keDependent);
+ }
+ // Check hi ranges if they are dependent and not unknown.
+ if ((r1hi.IsDependent() && !r1hi.IsUnknown()) || (r2hi.IsDependent() && !r2hi.IsUnknown()))
+ {
+ result.uLimit = Limit(Limit::keDependent);
+ }
+
+ if (r1lo.IsConstant())
+ {
+ result.lLimit = MultiplyConstantLimit(r1lo, r2lo);
+ }
+ if (r2lo.IsConstant())
+ {
+ result.lLimit = MultiplyConstantLimit(r2lo, r1lo);
+ }
+ if (r1hi.IsConstant())
+ {
+ result.uLimit = MultiplyConstantLimit(r1hi, r2hi);
+ }
+ if (r2hi.IsConstant())
+ {
+ result.uLimit = MultiplyConstantLimit(r2hi, r1hi);
+ }
+ return result;
+ }
+
// Given two ranges "r1" and "r2", do a Phi merge. If "monIncreasing" is true,
// then ignore the dependent variables for the lower bound but not for the upper bound.
static Range Merge(Range& r1, Range& r2, bool monIncreasing)
@@ -378,6 +456,32 @@ struct RangeOps
}
return result;
}
+
+ // Given a Range C from an op (x << C), convert it to be used as
+ // (x * C'), where C' is a power of 2.
+ static Range ConvertShiftToMultiply(Range& r1)
+ {
+ Limit& r1lo = r1.LowerLimit();
+ Limit& r1hi = r1.UpperLimit();
+
+ if (!r1lo.IsConstant() || !r1hi.IsConstant())
+ {
+ return Limit(Limit::keUnknown);
+ }
+
+ // Keep it simple for now, check if 0 <= C < 31
+ int r1loConstant = r1lo.GetConstant();
+ int r1hiConstant = r1hi.GetConstant();
+ if (r1loConstant <= 0 || r1loConstant > 31 || r1hiConstant <= 0 || r1hiConstant > 31)
+ {
+ return Limit(Limit::keUnknown);
+ }
+
+ Range result = Limit(Limit::keConstant);
+ result.lLimit = Limit(Limit::keConstant, 1 << r1loConstant);
+ result.uLimit = Limit(Limit::keConstant, 1 << r1hiConstant);
+ return result;
+ }
};
class RangeCheck
@@ -484,6 +588,9 @@ class RangeCheck
// Does the addition of the two limits overflow?
bool AddOverflows(Limit& limit1, Limit& limit2);
+ // Does the multiplication of the two limits overflow?
+ bool MultiplyOverflows(Limit& limit1, Limit& limit2);
+
// Does the binary operation between the operands overflow? Check recursively.
bool DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop);
diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp
index aae9f1bca07ace..5e54ca8bd94d46 100644
--- a/src/coreclr/jit/rationalize.cpp
+++ b/src/coreclr/jit/rationalize.cpp
@@ -482,8 +482,7 @@ void Rationalizer::RewriteAssignment(LIR::Use& use)
storeOper = GT_STORE_OBJ;
break;
case GT_DYN_BLK:
- storeOper = GT_STORE_DYN_BLK;
- storeBlk->AsDynBlk()->gtEvalSizeFirst = false;
+ storeOper = GT_STORE_DYN_BLK;
break;
default:
unreached();
diff --git a/src/coreclr/jit/redundantbranchopts.cpp b/src/coreclr/jit/redundantbranchopts.cpp
index d8e4f97e68cf82..5417308a9bd00f 100644
--- a/src/coreclr/jit/redundantbranchopts.cpp
+++ b/src/coreclr/jit/redundantbranchopts.cpp
@@ -1027,7 +1027,7 @@ bool Compiler::optRedundantRelop(BasicBlock* const block)
for (unsigned int i = 0; i < definedLocalsCount; i++)
{
- if (gtHasRef(prevTreeRHS, definedLocals[i], /*def only*/ false))
+ if (gtHasRef(prevTreeRHS, definedLocals[i]))
{
JITDUMP(" -- prev tree ref to V%02u interferes\n", definedLocals[i]);
interferes = true;
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index e4d18a9a0c9f91..af8d3752199176 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -8827,6 +8827,7 @@ void Compiler::fgValueNumberTree(GenTree* tree)
vnStore->VNPUnpackExc(addr->gtVNPair, &addrNvnp, &addrXvnp);
// Is the dereference immutable? If so, model it as referencing the read-only heap.
+ // TODO-VNTypes: this code needs to encode the types of the indirections.
if (tree->gtFlags & GTF_IND_INVARIANT)
{
assert(!isVolatile); // We don't expect both volatile and invariant
@@ -8849,22 +8850,13 @@ void Compiler::fgValueNumberTree(GenTree* tree)
if (!wasNewobj)
{
-
// Is this invariant indirect expected to always return a non-null value?
+ // TODO-VNTypes: non-null indirects should only be used for TYP_REFs.
if ((tree->gtFlags & GTF_IND_NONNULL) != 0)
{
assert(tree->gtFlags & GTF_IND_NONFAULTING);
tree->gtVNPair = vnStore->VNPairForFunc(tree->TypeGet(), VNF_NonNullIndirect, addrNvnp);
- if (addr->IsCnsIntOrI())
- {
- assert(addrXvnp.BothEqual() &&
- (addrXvnp.GetLiberal() == ValueNumStore::VNForEmptyExcSet()));
- }
- else
- {
- assert(false && "it's not expected to be hit at the moment, but can be allowed.");
- // tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
- }
+ tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
}
else
{
@@ -9452,7 +9444,7 @@ void Compiler::fgValueNumberIntrinsic(GenTree* tree)
}
else
{
- assert(intrinsic->gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType);
+ assert(intrinsic->gtIntrinsicName == NI_System_Object_GetType);
intrinsic->gtVNPair =
vnStore->VNPWithExc(vnStore->VNPairForFunc(intrinsic->TypeGet(), VNF_ObjGetType, arg0VNP), arg0VNPx);
}
diff --git a/src/coreclr/nativeaot/Bootstrap/CMakeLists.txt b/src/coreclr/nativeaot/Bootstrap/CMakeLists.txt
new file mode 100644
index 00000000000000..02fb30aad9f0c3
--- /dev/null
+++ b/src/coreclr/nativeaot/Bootstrap/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(base)
+add_subdirectory(dll)
diff --git a/src/coreclr/nativeaot/Bootstrap/base/CMakeLists.txt b/src/coreclr/nativeaot/Bootstrap/base/CMakeLists.txt
new file mode 100644
index 00000000000000..2366cd267bff56
--- /dev/null
+++ b/src/coreclr/nativeaot/Bootstrap/base/CMakeLists.txt
@@ -0,0 +1,15 @@
+project(bootstrapper)
+
+set(SOURCES
+ ../main.cpp
+)
+
+add_library(bootstrapper STATIC ${SOURCES})
+
+install_static_library(bootstrapper aotsdk nativeaot)
+
+if (CLR_CMAKE_TARGET_WIN32)
+ add_library(bootstrapper.GuardCF STATIC ${SOURCES})
+ install_static_library(bootstrapper.GuardCF aotsdk nativeaot)
+ target_compile_options(bootstrapper.GuardCF PRIVATE $<$,$>:/guard:cf>)
+endif()
diff --git a/src/coreclr/nativeaot/Bootstrap/dll/CMakeLists.txt b/src/coreclr/nativeaot/Bootstrap/dll/CMakeLists.txt
new file mode 100644
index 00000000000000..02fe16cb2825ba
--- /dev/null
+++ b/src/coreclr/nativeaot/Bootstrap/dll/CMakeLists.txt
@@ -0,0 +1,17 @@
+project(bootstrapperdll)
+
+add_definitions(-DCORERT_DLL)
+
+set(SOURCES
+ ../main.cpp
+)
+
+add_library(bootstrapperdll STATIC ${SOURCES})
+
+install_static_library(bootstrapperdll aotsdk nativeaot)
+
+if (CLR_CMAKE_TARGET_WIN32)
+ add_library(bootstrapperdll.GuardCF STATIC ${SOURCES})
+ install_static_library(bootstrapperdll.GuardCF aotsdk nativeaot)
+ target_compile_options(bootstrapperdll.GuardCF PRIVATE $<$,$>:/guard:cf>)
+endif()
diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp
new file mode 100644
index 00000000000000..798c4db7481c9a
--- /dev/null
+++ b/src/coreclr/nativeaot/Bootstrap/main.cpp
@@ -0,0 +1,228 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include
+
+//
+// This is the mechanism whereby multiple linked modules contribute their global data for initialization at
+// startup of the application.
+//
+// ILC creates sections in the output obj file to mark the beginning and end of merged global data.
+// It defines sentinel symbols that are used to get the addresses of the start and end of global data
+// at runtime. The section names are platform-specific to match platform-specific linker conventions.
+//
+#if defined(_MSC_VER)
+
+#pragma section(".modules$A", read)
+#pragma section(".modules$Z", read)
+extern "C" __declspec(allocate(".modules$A")) void * __modules_a[];
+extern "C" __declspec(allocate(".modules$Z")) void * __modules_z[];
+
+__declspec(allocate(".modules$A")) void * __modules_a[] = { nullptr };
+__declspec(allocate(".modules$Z")) void * __modules_z[] = { nullptr };
+
+//
+// Each obj file compiled from managed code has a .modules$I section containing a pointer to its ReadyToRun
+// data (which points at eager class constructors, frozen strings, etc).
+//
+// The #pragma ... /merge directive folds the book-end sections and all .modules$I sections from all input
+// obj files into .rdata in alphabetical order.
+//
+#pragma comment(linker, "/merge:.modules=.rdata")
+
+//
+// Unboxing stubs need to be merged, folded and sorted. They are delimited by two special sections (.unbox$A
+// and .unbox$Z). All unboxing stubs are in .unbox$M sections.
+//
+#pragma comment(linker, "/merge:.unbox=.text")
+
+char _bookend_a;
+char _bookend_z;
+
+//
+// Generate bookends for the managed code section.
+// We give them unique bodies to prevent folding.
+//
+
+#pragma code_seg(".managedcode$A")
+void* __managedcode_a() { return &_bookend_a; }
+#pragma code_seg(".managedcode$Z")
+void* __managedcode_z() { return &_bookend_z; }
+#pragma code_seg()
+
+//
+// Generate bookends for the unboxing stub section.
+// We give them unique bodies to prevent folding.
+//
+
+#pragma code_seg(".unbox$A")
+void* __unbox_a() { return &_bookend_a; }
+#pragma code_seg(".unbox$Z")
+void* __unbox_z() { return &_bookend_z; }
+#pragma code_seg()
+
+#else // _MSC_VER
+
+#if defined(__APPLE__)
+
+extern void * __modules_a[] __asm("section$start$__DATA$__modules");
+extern void * __modules_z[] __asm("section$end$__DATA$__modules");
+extern char __managedcode_a __asm("section$start$__TEXT$__managedcode");
+extern char __managedcode_z __asm("section$end$__TEXT$__managedcode");
+extern char __unbox_a __asm("section$start$__TEXT$__unbox");
+extern char __unbox_z __asm("section$end$__TEXT$__unbox");
+
+#else // __APPLE__
+
+extern "C" void * __start___modules[];
+extern "C" void * __stop___modules[];
+static void * (&__modules_a)[] = __start___modules;
+static void * (&__modules_z)[] = __stop___modules;
+
+extern "C" char __start___managedcode;
+extern "C" char __stop___managedcode;
+static char& __managedcode_a = __start___managedcode;
+static char& __managedcode_z = __stop___managedcode;
+
+extern "C" char __start___unbox;
+extern "C" char __stop___unbox;
+static char& __unbox_a = __start___unbox;
+static char& __unbox_z = __stop___unbox;
+
+#endif // __APPLE__
+
+#endif // _MSC_VER
+
+extern "C" bool RhInitialize();
+extern "C" void RhpEnableConservativeStackReporting();
+extern "C" void RhpShutdown();
+extern "C" void RhSetRuntimeInitializationCallback(int (*fPtr)());
+
+extern "C" bool RhRegisterOSModule(void * pModule,
+ void * pvManagedCodeStartRange, uint32_t cbManagedCodeRange,
+ void * pvUnboxingStubsStartRange, uint32_t cbUnboxingStubsRange,
+ void ** pClasslibFunctions, uint32_t nClasslibFunctions);
+
+extern "C" void* PalGetModuleHandleFromPointer(void* pointer);
+
+extern "C" void GetRuntimeException();
+extern "C" void FailFast();
+extern "C" void AppendExceptionStackFrame();
+extern "C" void GetSystemArrayEEType();
+extern "C" void OnFirstChanceException();
+extern "C" void OnUnhandledException();
+extern "C" void IDynamicCastableIsInterfaceImplemented();
+extern "C" void IDynamicCastableGetInterfaceImplementation();
+
+typedef void(*pfn)();
+
+static const pfn c_classlibFunctions[] = {
+ &GetRuntimeException,
+ &FailFast,
+ nullptr, // &UnhandledExceptionHandler,
+ &AppendExceptionStackFrame,
+ nullptr, // &CheckStaticClassConstruction,
+ &GetSystemArrayEEType,
+ &OnFirstChanceException,
+ &OnUnhandledException,
+ &IDynamicCastableIsInterfaceImplemented,
+ &IDynamicCastableGetInterfaceImplementation,
+};
+
+#ifndef _countof
+#define _countof(_array) (sizeof(_array)/sizeof(_array[0]))
+#endif
+
+extern "C" void InitializeModules(void* osModule, void ** modules, int count, void ** pClasslibFunctions, int nClasslibFunctions);
+
+#ifndef CORERT_DLL
+#define CORERT_ENTRYPOINT __managed__Main
+#if defined(_WIN32)
+extern "C" int __managed__Main(int argc, wchar_t* argv[]);
+#else
+extern "C" int __managed__Main(int argc, char* argv[]);
+#endif
+#else
+#define CORERT_ENTRYPOINT __managed__Startup
+extern "C" void __managed__Startup();
+#endif // !CORERT_DLL
+
+static int InitializeRuntime()
+{
+ if (!RhInitialize())
+ return -1;
+
+ // RhpEnableConservativeStackReporting();
+
+ void * osModule = PalGetModuleHandleFromPointer((void*)&CORERT_ENTRYPOINT);
+
+ // TODO: pass struct with parameters instead of the large signature of RhRegisterOSModule
+ if (!RhRegisterOSModule(
+ osModule,
+ (void*)&__managedcode_a, (uint32_t)((char *)&__managedcode_z - (char*)&__managedcode_a),
+ (void*)&__unbox_a, (uint32_t)((char *)&__unbox_z - (char*)&__unbox_a),
+ (void **)&c_classlibFunctions, _countof(c_classlibFunctions)))
+ {
+ return -1;
+ }
+
+ InitializeModules(osModule, __modules_a, (int)((__modules_z - __modules_a)), (void **)&c_classlibFunctions, _countof(c_classlibFunctions));
+
+#ifdef CORERT_DLL
+ // Run startup method immediately for a native library
+ __managed__Startup();
+#endif // CORERT_DLL
+
+ return 0;
+}
+
+#ifndef CORERT_DLL
+
+#ifdef ENSURE_PRIMARY_STACK_SIZE
+__attribute__((noinline, optnone))
+static void EnsureStackSize(int stackSize)
+{
+ volatile char* s = (char*)_alloca(stackSize);
+ *s = 0;
+}
+#endif // ENSURE_PRIMARY_STACK_SIZE
+
+#if defined(_WIN32)
+int __cdecl wmain(int argc, wchar_t* argv[])
+#else
+int main(int argc, char* argv[])
+#endif
+{
+#ifdef ENSURE_PRIMARY_STACK_SIZE
+ // TODO: https://github.com/dotnet/runtimelab/issues/791
+ EnsureStackSize(1536 * 1024);
+#endif
+
+ int initval = InitializeRuntime();
+ if (initval != 0)
+ return initval;
+
+ int retval = __managed__Main(argc, argv);
+
+ RhpShutdown();
+
+ return retval;
+}
+#endif // !CORERT_DLL
+
+#ifdef CORERT_DLL
+static struct InitializeRuntimePointerHelper
+{
+ InitializeRuntimePointerHelper()
+ {
+ RhSetRuntimeInitializationCallback(&InitializeRuntime);
+ }
+} initializeRuntimePointerHelper;
+
+extern "C" void* CoreRT_StaticInitialization();
+
+void* CoreRT_StaticInitialization()
+{
+ return &initializeRuntimePointerHelper;
+}
+#endif // CORERT_DLL
diff --git a/src/coreclr/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj b/src/coreclr/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj
new file mode 100644
index 00000000000000..6469964c0170a1
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/BuildFrameworkNativeObjects.proj
@@ -0,0 +1,47 @@
+
+
+
+ ComputeIlcCompileInputs;BuildOneFrameworkLibrary;SetupOSSpecificProps
+ BuildAllFrameworkLibrariesAsSingleLib
+ true
+ $(FrameworkObjPath)\
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+ LibraryToCompile=%(DefaultFrameworkAssemblies.Identity)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj b/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj
new file mode 100644
index 00000000000000..624760868cf2de
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj
@@ -0,0 +1,17 @@
+
+
+
+
+ $(RuntimeBinDir)/build/
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/CoreRTNatVis.natvis b/src/coreclr/nativeaot/BuildIntegration/CoreRTNatVis.natvis
new file mode 100644
index 00000000000000..bd5ebc5f660d9d
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/CoreRTNatVis.natvis
@@ -0,0 +1,80 @@
+
+
+
+ {&(_firstChar),su}
+ &(_firstChar),su
+
+
+ {{count = {_numComponents}}}
+
+
+ _numComponents
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1**)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+ ($T1*)(((char*)this)+sizeof(void*)+sizeof(void*))
+
+
+
+
+
+
+
+
+
+ Null
+ {*Get()}
+
+ Get()
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.targets
new file mode 100644
index 00000000000000..f1bb8ce6e9610a
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.targets
@@ -0,0 +1,55 @@
+
+
+
+
+
+ win
+ osx
+ linux-musl
+ linux
+
+
+ $(RuntimeIdentifier)-
+ x86
+ x64
+ arm
+ arm64
+ unknown
+
+ runtime.$(OSIdentifier)-$(TargetArchitecture).Microsoft.DotNet.ILCompiler
+
+ $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant)
+
+
+ arm64
+
+ $(OSHostArch)
+ runtime.$(OSIdentifier)-$(IlcHostArch).Microsoft.DotNet.ILCompiler
+ true
+
+
+
+
+
+
+ RunResolvePackageDependencies
+ ImportRuntimeIlcPackageTarget
+ SetupProperties
+
+
+
+
+
+
+
+
+
+ %(PackageDefinitions.ResolvedPath)
+ %(PackageDefinitions.ResolvedPath)
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
new file mode 100644
index 00000000000000..67efba61efde98
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ResolvedCopyLocalPublishAssets Remove="@(_AssembliesToSkipPublish)" />
+ <_ResolvedCopyLocalPublishAssets Include="@(_LinkedResolvedAssemblies)" />
+
+
+
+ <_NativeIntermediateAssembly Include="@(IntermediateAssembly->'$(NativeOutputPath)%(Filename)$(NativeBinaryExt)')" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props
new file mode 100644
index 00000000000000..e486925e1eeba2
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.props
@@ -0,0 +1,110 @@
+
+
+
+ clang
+ $(CppCompilerAndLinker)
+ $(CppCompilerAndLinker)
+ ar
+
+
+
+
+
+ libRuntime.WorkstationGC
+ libRuntime.ServerGC
+
+
+ $(RuntimeIdentifier)
+
+
+ x86_64
+ aarch64
+
+
+ $(CrossCompileArch)-linux-gnu
+ $(CrossCompileArch)-alpine-linux-musl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(IlcPath)/framework/lib%(Identity).a
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props
new file mode 100644
index 00000000000000..32cb494f28fa1e
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Windows.props
@@ -0,0 +1,118 @@
+
+
+
+ cl
+ link
+ lib
+ .lib
+ .GuardCF.lib
+ Runtime.WorkstationGC
+ Runtime.ServerGC
+ bootstrapper
+ bootstrapperdll
+ wmainCRTStartup
+ WINDOWS
+ CONSOLE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(IlcPath)\sdk\%(Identity).Aot$(LibrarySuffix)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_CppToolsDirectory>$(_FindVCVarsallOutput.Split(`#`)[0])
+ "$(_CppToolsDirectory)cl.exe"
+ "$(_CppToolsDirectory)link.exe"
+ "$(_CppToolsDirectory)lib.exe"
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
new file mode 100644
index 00000000000000..2d353a4dc2e90b
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -0,0 +1,384 @@
+
+
+
+
+
+ $(IntermediateOutputPath)native\
+ $(OutputPath)native\
+ true
+ $(MSBuildThisFileDirectory)..\tools\netstandard\ILCompiler.Build.Tasks.dll
+ $(IlcPath)
+ windows
+ OSX
+ $(OS)
+ true
+
+ false
+ true
+
+
+
+
+ <_BuildingInCompatibleMode Condition="$(TrimmerDefaultAction) == '' and $(IlcGenerateStackTraceData) == '' and $(IlcDisableReflection) == ''">true
+
+ true
+ true
+ true
+ copyused
+
+
+
+
+ false
+ true
+ false
+
+
+
+ .obj
+ .o
+
+ .lib
+ .a
+
+ $(NativeObjectExt)
+
+ true
+
+ .exe
+
+ .dll
+ .dylib
+ .so
+ .lib
+ .a
+
+ .def
+ .exports
+
+ $(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)
+ $(NativeOutputPath)$(TargetName)$(NativeBinaryExt)
+ $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)
+
+ $(NativeObject)
+
+ IlcCompile
+
+ $(NativeOutputPath)
+ $(NativeIntermediateOutputPath)
+
+ $(FrameworkLibPath)\Framework$(LibFileExt)
+ $(FrameworkLibPath)\libframework$(LibFileExt)
+ SetupProperties
+
+
+
+ Compile;ComputeIlcCompileInputs
+ $(IlcCompileDependsOn);BuildFrameworkLib
+ $(IlcCompileDependsOn);SetupOSSpecificProps
+ $(IlcCompileDependsOn);PrepareForILLink
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ExcludedPrivateSdkAssemblies Include="$(IlcPath)\sdk\System.Private.Reflection.Core.dll" Condition="$(IlcDisableReflection) == 'true'" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ $(IlcHostPackagePath)
+ $(RuntimePackagePath)
+
+
+
+
+ <_ExcludedPrivateSdkAssemblies Include="$(IlcPath)\sdk\System.Private.Reflection.Core.dll" Condition="$(IlcDisableReflection) == 'true'" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IntermediateOutputPath=$(IntermediateOutputPath);
+ FrameworkLibPath=$(FrameworkLibPath);
+ FrameworkObjPath=$(FrameworkObjPath);
+ RuntimePackagePath=$(RuntimePackagePath);
+ IlcHostPackagePath=$(IlcHostPackagePath);
+ TargetArchitecture=$(TargetArchitecture);
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ <__SingleWarnIntermediateAssembly Include="@(ManagedAssemblyToLink)" />
+ <__SingleWarnIntermediateAssembly Remove="@(IntermediateAssembly)" />
+
+ <_SingleWarnIntermediateAssembly Include="@(ManagedAssemblyToLink)" />
+ <_SingleWarnIntermediateAssembly Remove="@(__SingleWarnIntermediateAssembly)" />
+
+ <_SingleWarnIntermediateAssembly>
+ false
+
+
+
+
+
+
+
+ false
+
+
+
+
+ <_IlcRootedAssemblies Include="@(TrimmerRootAssembly)" />
+ <_IlcRootedAssemblies Include="@(ManagedAssemblyToLink)" Condition="%(ManagedAssemblyToLink.TrimMode) == 'copy'" />
+ <_IlcConditionallyRootedAssemblies Include="@(ManagedAssemblyToLink)" Condition="%(ManagedAssemblyToLink.TrimMode) == 'copyused'" />
+ <_IlcTrimmedAssemblies Include="@(ManagedAssemblyToLink)" Condition="%(ManagedAssemblyToLink.TrimMode) == 'link'" />
+ <_IlcNoSingleWarnAssemblies Include="@(ManagedAssemblyToLink)" Condition="%(ManagedAssemblyToLink.TrimmerSingleWarn) == 'false'" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_Win32ResFile>$(NativeIntermediateOutputPath)$(TargetName).res
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_IgnoreLinkerWarnings>false
+ <_IgnoreLinkerWarnings Condition="'$(TargetOS)' == 'OSX'">true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/nativeaot/BuildIntegration/WindowsAPIs.txt b/src/coreclr/nativeaot/BuildIntegration/WindowsAPIs.txt
new file mode 100644
index 00000000000000..845a90ca278443
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/WindowsAPIs.txt
@@ -0,0 +1,2336 @@
+# List of ubiquitous Windows APIs that are safe to emit direct calls for
+#
+# This list was seeded from mincore.lib in Windows SDK. Rarely used .libs, and APIs not available
+# on all Windows editions (including Windows 7 and Windows Nano) were removed.
+#
+
+advapi32!AbortSystemShutdownW
+advapi32!AccessCheck
+advapi32!AccessCheckAndAuditAlarmW
+advapi32!AccessCheckByType
+advapi32!AccessCheckByTypeAndAuditAlarmW
+advapi32!AccessCheckByTypeResultList
+advapi32!AccessCheckByTypeResultListAndAuditAlarmByHandleW
+advapi32!AccessCheckByTypeResultListAndAuditAlarmW
+advapi32!AddAccessAllowedAce
+advapi32!AddAccessAllowedAceEx
+advapi32!AddAccessAllowedObjectAce
+advapi32!AddAccessDeniedAce
+advapi32!AddAccessDeniedAceEx
+advapi32!AddAccessDeniedObjectAce
+advapi32!AddAce
+advapi32!AddAuditAccessAce
+advapi32!AddAuditAccessAceEx
+advapi32!AddAuditAccessObjectAce
+advapi32!AddMandatoryAce
+advapi32!AdjustTokenGroups
+advapi32!AdjustTokenPrivileges
+advapi32!AllocateAndInitializeSid
+advapi32!AllocateLocallyUniqueId
+advapi32!AreAllAccessesGranted
+advapi32!AreAnyAccessesGranted
+advapi32!ChangeServiceConfig2A
+advapi32!ChangeServiceConfig2W
+advapi32!ChangeServiceConfigA
+advapi32!ChangeServiceConfigW
+advapi32!CheckTokenMembership
+advapi32!CloseServiceHandle
+advapi32!CloseTrace
+advapi32!ControlService
+advapi32!ControlServiceExA
+advapi32!ControlServiceExW
+advapi32!ControlTraceW
+advapi32!ConvertSecurityDescriptorToStringSecurityDescriptorW
+advapi32!ConvertSidToStringSidW
+advapi32!ConvertStringSecurityDescriptorToSecurityDescriptorW
+advapi32!ConvertStringSidToSidW
+advapi32!ConvertToAutoInheritPrivateObjectSecurity
+advapi32!CopySid
+advapi32!CreatePrivateObjectSecurity
+advapi32!CreatePrivateObjectSecurityEx
+advapi32!CreatePrivateObjectSecurityWithMultipleInheritance
+advapi32!CreateProcessAsUserA
+advapi32!CreateProcessAsUserW
+advapi32!CreateRestrictedToken
+advapi32!CreateServiceA
+advapi32!CreateServiceW
+advapi32!CreateWellKnownSid
+advapi32!CredDeleteA
+advapi32!CredDeleteW
+advapi32!CredEnumerateA
+advapi32!CredEnumerateW
+advapi32!CredFindBestCredentialA
+advapi32!CredFindBestCredentialW
+advapi32!CredFree
+advapi32!CredGetSessionTypes
+advapi32!CredGetTargetInfoA
+advapi32!CredGetTargetInfoW
+advapi32!CredIsMarshaledCredentialW
+advapi32!CredIsProtectedA
+advapi32!CredIsProtectedW
+advapi32!CredMarshalCredentialA
+advapi32!CredMarshalCredentialW
+advapi32!CredProtectA
+advapi32!CredProtectW
+advapi32!CredReadA
+advapi32!CredReadDomainCredentialsA
+advapi32!CredReadDomainCredentialsW
+advapi32!CredReadW
+advapi32!CredUnmarshalCredentialA
+advapi32!CredUnmarshalCredentialW
+advapi32!CredUnprotectA
+advapi32!CredUnprotectW
+advapi32!CredWriteA
+advapi32!CredWriteDomainCredentialsA
+advapi32!CredWriteDomainCredentialsW
+advapi32!CredWriteW
+advapi32!DeleteAce
+advapi32!DeleteService
+advapi32!DestroyPrivateObjectSecurity
+advapi32!DuplicateToken
+advapi32!DuplicateTokenEx
+advapi32!EnableTraceEx2
+advapi32!EnumDependentServicesW
+advapi32!EnumerateTraceGuidsEx
+advapi32!EnumServicesStatusExW
+advapi32!EqualDomainSid
+advapi32!EqualPrefixSid
+advapi32!EqualSid
+advapi32!EventAccessControl
+advapi32!EventAccessQuery
+advapi32!EventAccessRemove
+advapi32!EventActivityIdControl
+advapi32!EventEnabled
+advapi32!EventProviderEnabled
+advapi32!EventRegister
+advapi32!EventSetInformation
+advapi32!EventUnregister
+advapi32!EventWrite
+advapi32!EventWriteEx
+advapi32!EventWriteString
+advapi32!EventWriteTransfer
+advapi32!FindFirstFreeAce
+advapi32!FreeSid
+advapi32!GetAce
+advapi32!GetAclInformation
+advapi32!GetFileSecurityW
+advapi32!GetKernelObjectSecurity
+advapi32!GetLengthSid
+advapi32!GetPrivateObjectSecurity
+advapi32!GetSecurityDescriptorControl
+advapi32!GetSecurityDescriptorDacl
+advapi32!GetSecurityDescriptorGroup
+advapi32!GetSecurityDescriptorLength
+advapi32!GetSecurityDescriptorOwner
+advapi32!GetSecurityDescriptorRMControl
+advapi32!GetSecurityDescriptorSacl
+advapi32!GetServiceDisplayNameW
+advapi32!GetServiceKeyNameW
+advapi32!GetSidIdentifierAuthority
+advapi32!GetSidLengthRequired
+advapi32!GetSidSubAuthority
+advapi32!GetSidSubAuthorityCount
+advapi32!GetTokenInformation
+advapi32!GetTraceEnableFlags
+advapi32!GetTraceEnableLevel
+advapi32!GetTraceLoggerHandle
+advapi32!GetWindowsAccountDomainSid
+advapi32!ImpersonateAnonymousToken
+advapi32!ImpersonateLoggedOnUser
+advapi32!ImpersonateNamedPipeClient
+advapi32!ImpersonateSelf
+advapi32!InitializeAcl
+advapi32!InitializeSecurityDescriptor
+advapi32!InitializeSid
+advapi32!InitiateShutdownW
+advapi32!InitiateSystemShutdownExW
+advapi32!IsTokenRestricted
+advapi32!IsValidAcl
+advapi32!IsValidSecurityDescriptor
+advapi32!IsValidSid
+advapi32!IsWellKnownSid
+advapi32!LogonUserExExW
+advapi32!LookupAccountNameW
+advapi32!LookupAccountSidW
+advapi32!LookupPrivilegeDisplayNameW
+advapi32!LookupPrivilegeNameW
+advapi32!LookupPrivilegeValueW
+advapi32!LsaEnumerateTrustedDomains
+advapi32!LsaManageSidNameMapping
+advapi32!MakeAbsoluteSD
+advapi32!MakeSelfRelativeSD
+advapi32!MapGenericMask
+advapi32!NotifyServiceStatusChangeA
+advapi32!NotifyServiceStatusChangeW
+advapi32!ObjectCloseAuditAlarmW
+advapi32!ObjectDeleteAuditAlarmW
+advapi32!ObjectOpenAuditAlarmW
+advapi32!ObjectPrivilegeAuditAlarmW
+advapi32!OpenProcessToken
+advapi32!OpenSCManagerA
+advapi32!OpenSCManagerW
+advapi32!OpenServiceA
+advapi32!OpenServiceW
+advapi32!OpenThreadToken
+advapi32!OpenTraceW
+advapi32!PrivilegeCheck
+advapi32!PrivilegedServiceAuditAlarmW
+advapi32!ProcessTrace
+advapi32!QueryAllTracesW
+advapi32!QuerySecurityAccessMask
+advapi32!QueryServiceConfig2A
+advapi32!QueryServiceConfig2W
+advapi32!QueryServiceConfigA
+advapi32!QueryServiceConfigW
+advapi32!QueryServiceObjectSecurity
+advapi32!QueryServiceStatus
+advapi32!QueryServiceStatusEx
+advapi32!RegCloseKey
+advapi32!RegCopyTreeW
+advapi32!RegCreateKeyExA
+advapi32!RegCreateKeyExW
+advapi32!RegDeleteKeyExA
+advapi32!RegDeleteKeyExW
+advapi32!RegDeleteKeyValueA
+advapi32!RegDeleteKeyValueW
+advapi32!RegDeleteTreeA
+advapi32!RegDeleteTreeW
+advapi32!RegDeleteValueA
+advapi32!RegDeleteValueW
+advapi32!RegDisablePredefinedCacheEx
+advapi32!RegEnumKeyExA
+advapi32!RegEnumKeyExW
+advapi32!RegEnumValueA
+advapi32!RegEnumValueW
+advapi32!RegFlushKey
+advapi32!RegGetKeySecurity
+advapi32!RegGetValueA
+advapi32!RegGetValueW
+advapi32!RegisterServiceCtrlHandlerA
+advapi32!RegisterServiceCtrlHandlerExA
+advapi32!RegisterServiceCtrlHandlerExW
+advapi32!RegisterServiceCtrlHandlerW
+advapi32!RegisterTraceGuidsW
+advapi32!RegLoadAppKeyA
+advapi32!RegLoadAppKeyW
+advapi32!RegLoadKeyA
+advapi32!RegLoadKeyW
+advapi32!RegLoadMUIStringA
+advapi32!RegLoadMUIStringW
+advapi32!RegNotifyChangeKeyValue
+advapi32!RegOpenCurrentUser
+advapi32!RegOpenKeyExA
+advapi32!RegOpenKeyExW
+advapi32!RegOpenUserClassesRoot
+advapi32!RegQueryInfoKeyA
+advapi32!RegQueryInfoKeyW
+advapi32!RegQueryMultipleValuesA
+advapi32!RegQueryMultipleValuesW
+advapi32!RegQueryValueExA
+advapi32!RegQueryValueExW
+advapi32!RegRestoreKeyA
+advapi32!RegRestoreKeyW
+advapi32!RegSaveKeyExA
+advapi32!RegSaveKeyExW
+advapi32!RegSetKeySecurity
+advapi32!RegSetKeyValueA
+advapi32!RegSetKeyValueW
+advapi32!RegSetValueExA
+advapi32!RegSetValueExW
+advapi32!RegUnLoadKeyA
+advapi32!RegUnLoadKeyW
+advapi32!RevertToSelf
+advapi32!SetAclInformation
+advapi32!SetFileSecurityW
+advapi32!SetKernelObjectSecurity
+advapi32!SetPrivateObjectSecurity
+advapi32!SetPrivateObjectSecurityEx
+advapi32!SetSecurityAccessMask
+advapi32!SetSecurityDescriptorControl
+advapi32!SetSecurityDescriptorDacl
+advapi32!SetSecurityDescriptorGroup
+advapi32!SetSecurityDescriptorOwner
+advapi32!SetSecurityDescriptorRMControl
+advapi32!SetSecurityDescriptorSacl
+advapi32!SetServiceObjectSecurity
+advapi32!SetServiceStatus
+advapi32!SetThreadToken
+advapi32!SetTokenInformation
+advapi32!StartServiceA
+advapi32!StartServiceCtrlDispatcherA
+advapi32!StartServiceCtrlDispatcherW
+advapi32!StartServiceW
+advapi32!StartTraceW
+advapi32!StopTraceW
+advapi32!SystemFunction001
+advapi32!SystemFunction002
+advapi32!SystemFunction003
+advapi32!SystemFunction004
+advapi32!SystemFunction005
+advapi32!SystemFunction028
+advapi32!SystemFunction029
+advapi32!SystemFunction034
+advapi32!SystemFunction036
+advapi32!SystemFunction040
+advapi32!SystemFunction041
+advapi32!TraceEvent
+advapi32!TraceMessage
+advapi32!TraceMessageVa
+advapi32!TraceSetInformation
+advapi32!UnregisterTraceGuids
+bcrypt!BCryptAddContextFunction
+bcrypt!BCryptCloseAlgorithmProvider
+bcrypt!BCryptConfigureContext
+bcrypt!BCryptConfigureContextFunction
+bcrypt!BCryptCreateContext
+bcrypt!BCryptCreateHash
+bcrypt!BCryptDecrypt
+bcrypt!BCryptDeleteContext
+bcrypt!BCryptDeriveKey
+bcrypt!BCryptDeriveKeyCapi
+bcrypt!BCryptDeriveKeyPBKDF2
+bcrypt!BCryptDestroyHash
+bcrypt!BCryptDestroyKey
+bcrypt!BCryptDestroySecret
+bcrypt!BCryptDuplicateHash
+bcrypt!BCryptDuplicateKey
+bcrypt!BCryptEncrypt
+bcrypt!BCryptEnumAlgorithms
+bcrypt!BCryptEnumContextFunctionProviders
+bcrypt!BCryptEnumContextFunctions
+bcrypt!BCryptEnumContexts
+bcrypt!BCryptEnumProviders
+bcrypt!BCryptEnumRegisteredProviders
+bcrypt!BCryptExportKey
+bcrypt!BCryptFinalizeKeyPair
+bcrypt!BCryptFinishHash
+bcrypt!BCryptFreeBuffer
+bcrypt!BCryptGenerateKeyPair
+bcrypt!BCryptGenerateSymmetricKey
+bcrypt!BCryptGenRandom
+bcrypt!BCryptGetFipsAlgorithmMode
+bcrypt!BCryptGetProperty
+bcrypt!BCryptHashData
+bcrypt!BCryptImportKey
+bcrypt!BCryptImportKeyPair
+bcrypt!BCryptOpenAlgorithmProvider
+bcrypt!BCryptQueryContextConfiguration
+bcrypt!BCryptQueryContextFunctionConfiguration
+bcrypt!BCryptQueryContextFunctionProperty
+bcrypt!BCryptQueryProviderRegistration
+bcrypt!BCryptRegisterConfigChangeNotify
+bcrypt!BCryptRemoveContextFunction
+bcrypt!BCryptResolveProviders
+bcrypt!BCryptSecretAgreement
+bcrypt!BCryptSetAuditingInterface
+bcrypt!BCryptSetContextFunctionProperty
+bcrypt!BCryptSetProperty
+bcrypt!BCryptSignHash
+bcrypt!BCryptUnregisterConfigChangeNotify
+bcrypt!BCryptVerifySignature
+crypt32!CertAddCertificateContextToStore
+crypt32!CertAddCertificateLinkToStore
+crypt32!CertAddCRLContextToStore
+crypt32!CertAddCRLLinkToStore
+crypt32!CertAddCTLContextToStore
+crypt32!CertAddCTLLinkToStore
+crypt32!CertAddEncodedCertificateToStore
+crypt32!CertAddEncodedCertificateToSystemStoreA
+crypt32!CertAddEncodedCertificateToSystemStoreW
+crypt32!CertAddEncodedCRLToStore
+crypt32!CertAddEncodedCTLToStore
+crypt32!CertAddEnhancedKeyUsageIdentifier
+crypt32!CertAddRefServerOcspResponse
+crypt32!CertAddRefServerOcspResponseContext
+crypt32!CertAddSerializedElementToStore
+crypt32!CertAddStoreToCollection
+crypt32!CertAlgIdToOID
+crypt32!CertCloseServerOcspResponse
+crypt32!CertCloseStore
+crypt32!CertCompareCertificate
+crypt32!CertCompareCertificateName
+crypt32!CertCompareIntegerBlob
+crypt32!CertComparePublicKeyInfo
+crypt32!CertControlStore
+crypt32!CertCreateCertificateChainEngine
+crypt32!CertCreateCertificateContext
+crypt32!CertCreateContext
+crypt32!CertCreateCRLContext
+crypt32!CertCreateCTLContext
+crypt32!CertCreateCTLEntryFromCertificateContextProperties
+crypt32!CertCreateSelfSignCertificate
+crypt32!CertDeleteCertificateFromStore
+crypt32!CertDeleteCRLFromStore
+crypt32!CertDeleteCTLFromStore
+crypt32!CertDuplicateCertificateChain
+crypt32!CertDuplicateCertificateContext
+crypt32!CertDuplicateCRLContext
+crypt32!CertDuplicateCTLContext
+crypt32!CertDuplicateStore
+crypt32!CertEnumCertificateContextProperties
+crypt32!CertEnumCertificatesInStore
+crypt32!CertEnumCRLContextProperties
+crypt32!CertEnumCRLsInStore
+crypt32!CertEnumCTLContextProperties
+crypt32!CertEnumCTLsInStore
+crypt32!CertEnumPhysicalStore
+crypt32!CertEnumSubjectInSortedCTL
+crypt32!CertEnumSystemStore
+crypt32!CertEnumSystemStoreLocation
+crypt32!CertFindAttribute
+crypt32!CertFindCertificateInCRL
+crypt32!CertFindCertificateInStore
+crypt32!CertFindChainInStore
+crypt32!CertFindCRLInStore
+crypt32!CertFindCTLInStore
+crypt32!CertFindExtension
+crypt32!CertFindRDNAttr
+crypt32!CertFindSubjectInCTL
+crypt32!CertFindSubjectInSortedCTL
+crypt32!CertFreeCertificateChain
+crypt32!CertFreeCertificateChainEngine
+crypt32!CertFreeCertificateChainList
+crypt32!CertFreeCertificateContext
+crypt32!CertFreeCRLContext
+crypt32!CertFreeCTLContext
+crypt32!CertFreeServerOcspResponseContext
+crypt32!CertGetCertificateChain
+crypt32!CertGetCertificateContextProperty
+crypt32!CertGetCRLContextProperty
+crypt32!CertGetCRLFromStore
+crypt32!CertGetCTLContextProperty
+crypt32!CertGetEnhancedKeyUsage
+crypt32!CertGetIntendedKeyUsage
+crypt32!CertGetIssuerCertificateFromStore
+crypt32!CertGetNameStringA
+crypt32!CertGetNameStringW
+crypt32!CertGetPublicKeyLength
+crypt32!CertGetServerOcspResponseContext
+crypt32!CertGetStoreProperty
+crypt32!CertGetSubjectCertificateFromStore
+crypt32!CertGetValidUsages
+crypt32!CertIsRDNAttrsInCertificateName
+crypt32!CertIsStrongHashToSign
+crypt32!CertIsValidCRLForCertificate
+crypt32!CertNameToStrA
+crypt32!CertNameToStrW
+crypt32!CertOIDToAlgId
+crypt32!CertOpenServerOcspResponse
+crypt32!CertOpenStore
+crypt32!CertOpenSystemStoreA
+crypt32!CertOpenSystemStoreW
+crypt32!CertRDNValueToStrA
+crypt32!CertRDNValueToStrW
+crypt32!CertRegisterPhysicalStore
+crypt32!CertRegisterSystemStore
+crypt32!CertRemoveEnhancedKeyUsageIdentifier
+crypt32!CertRemoveStoreFromCollection
+crypt32!CertResyncCertificateChainEngine
+crypt32!CertRetrieveLogoOrBiometricInfo
+crypt32!CertSaveStore
+crypt32!CertSelectCertificateChains
+crypt32!CertSerializeCertificateStoreElement
+crypt32!CertSerializeCRLStoreElement
+crypt32!CertSerializeCTLStoreElement
+crypt32!CertSetCertificateContextPropertiesFromCTLEntry
+crypt32!CertSetCertificateContextProperty
+crypt32!CertSetCRLContextProperty
+crypt32!CertSetCTLContextProperty
+crypt32!CertSetEnhancedKeyUsage
+crypt32!CertSetStoreProperty
+crypt32!CertStrToNameA
+crypt32!CertStrToNameW
+crypt32!CertUnregisterPhysicalStore
+crypt32!CertUnregisterSystemStore
+crypt32!CertVerifyCertificateChainPolicy
+crypt32!CertVerifyCRLRevocation
+crypt32!CertVerifyCRLTimeValidity
+crypt32!CertVerifyCTLUsage
+crypt32!CertVerifyRevocation
+crypt32!CertVerifySubjectCertificateContext
+crypt32!CertVerifyTimeValidity
+crypt32!CertVerifyValidityNesting
+crypt32!CryptAcquireCertificatePrivateKey
+crypt32!CryptBinaryToStringA
+crypt32!CryptBinaryToStringW
+crypt32!CryptCloseAsyncHandle
+crypt32!CryptCreateAsyncHandle
+crypt32!CryptCreateKeyIdentifierFromCSP
+crypt32!CryptDecodeMessage
+crypt32!CryptDecodeObject
+crypt32!CryptDecodeObjectEx
+crypt32!CryptDecryptAndVerifyMessageSignature
+crypt32!CryptDecryptMessage
+crypt32!CryptEncodeObject
+crypt32!CryptEncodeObjectEx
+crypt32!CryptEncryptMessage
+crypt32!CryptEnumKeyIdentifierProperties
+crypt32!CryptEnumOIDFunction
+crypt32!CryptEnumOIDInfo
+crypt32!CryptExportPKCS8
+crypt32!CryptExportPublicKeyInfo
+crypt32!CryptExportPublicKeyInfoEx
+crypt32!CryptExportPublicKeyInfoFromBCryptKeyHandle
+crypt32!CryptFindCertificateKeyProvInfo
+crypt32!CryptFindLocalizedName
+crypt32!CryptFindOIDInfo
+crypt32!CryptFormatObject
+crypt32!CryptFreeOIDFunctionAddress
+crypt32!CryptGetAsyncParam
+crypt32!CryptGetDefaultOIDDllList
+crypt32!CryptGetDefaultOIDFunctionAddress
+crypt32!CryptGetKeyIdentifierProperty
+crypt32!CryptGetMessageCertificates
+crypt32!CryptGetMessageSignerCount
+crypt32!CryptGetOIDFunctionAddress
+crypt32!CryptGetOIDFunctionValue
+crypt32!CryptHashCertificate
+crypt32!CryptHashCertificate2
+crypt32!CryptHashMessage
+crypt32!CryptHashPublicKeyInfo
+crypt32!CryptHashToBeSigned
+crypt32!CryptImportPKCS8
+crypt32!CryptImportPublicKeyInfo
+crypt32!CryptImportPublicKeyInfoEx
+crypt32!CryptImportPublicKeyInfoEx2
+crypt32!CryptInitOIDFunctionSet
+crypt32!CryptInstallDefaultContext
+crypt32!CryptInstallOIDFunctionAddress
+crypt32!CryptLoadSip
+crypt32!CryptMemAlloc
+crypt32!CryptMemFree
+crypt32!CryptMemRealloc
+crypt32!CryptMsgCalculateEncodedLength
+crypt32!CryptMsgClose
+crypt32!CryptMsgControl
+crypt32!CryptMsgCountersign
+crypt32!CryptMsgCountersignEncoded
+crypt32!CryptMsgDuplicate
+crypt32!CryptMsgEncodeAndSignCTL
+crypt32!CryptMsgGetAndVerifySigner
+crypt32!CryptMsgGetParam
+crypt32!CryptMsgOpenToDecode
+crypt32!CryptMsgOpenToEncode
+crypt32!CryptMsgSignCTL
+crypt32!CryptMsgUpdate
+crypt32!CryptMsgVerifyCountersignatureEncoded
+crypt32!CryptMsgVerifyCountersignatureEncodedEx
+crypt32!CryptProtectData
+crypt32!CryptProtectMemory
+crypt32!CryptQueryObject
+crypt32!CryptRegisterDefaultOIDFunction
+crypt32!CryptRegisterOIDFunction
+crypt32!CryptRegisterOIDInfo
+crypt32!CryptRetrieveTimeStamp
+crypt32!CryptSetAsyncParam
+crypt32!CryptSetKeyIdentifierProperty
+crypt32!CryptSetOIDFunctionValue
+crypt32!CryptSignAndEncodeCertificate
+crypt32!CryptSignAndEncryptMessage
+crypt32!CryptSignCertificate
+crypt32!CryptSignMessage
+crypt32!CryptSignMessageWithKey
+crypt32!CryptSIPAddProvider
+crypt32!CryptSIPCreateIndirectData
+crypt32!CryptSIPGetCaps
+crypt32!CryptSIPGetSignedDataMsg
+crypt32!CryptSIPLoad
+crypt32!CryptSIPPutSignedDataMsg
+crypt32!CryptSIPRemoveProvider
+crypt32!CryptSIPRemoveSignedDataMsg
+crypt32!CryptSIPRetrieveSubjectGuid
+crypt32!CryptSIPRetrieveSubjectGuidForCatalogFile
+crypt32!CryptSIPVerifyIndirectData
+crypt32!CryptStringToBinaryA
+crypt32!CryptStringToBinaryW
+crypt32!CryptUninstallDefaultContext
+crypt32!CryptUnprotectData
+crypt32!CryptUnprotectMemory
+crypt32!CryptUnregisterDefaultOIDFunction
+crypt32!CryptUnregisterOIDFunction
+crypt32!CryptUnregisterOIDInfo
+crypt32!CryptUpdateProtectedState
+crypt32!CryptVerifyCertificateSignature
+crypt32!CryptVerifyCertificateSignatureEx
+crypt32!CryptVerifyDetachedMessageHash
+crypt32!CryptVerifyDetachedMessageSignature
+crypt32!CryptVerifyMessageHash
+crypt32!CryptVerifyMessageSignature
+crypt32!CryptVerifyMessageSignatureWithKey
+crypt32!CryptVerifyTimeStampSignature
+crypt32!PFXExportCertStore
+crypt32!PFXExportCertStore2
+crypt32!PFXExportCertStoreEx
+crypt32!PFXImportCertStore
+crypt32!PFXIsPFXBlob
+crypt32!PFXVerifyPassword
+iphlpapi!AddIPAddress
+iphlpapi!AllocateAndGetInterfaceInfoFromStack
+iphlpapi!AllocateAndGetIpAddrTableFromStack
+iphlpapi!CancelIPChangeNotify
+iphlpapi!CancelMibChangeNotify2
+iphlpapi!ConvertGuidToStringA
+iphlpapi!ConvertGuidToStringW
+iphlpapi!ConvertInterfaceAliasToLuid
+iphlpapi!ConvertInterfaceGuidToLuid
+iphlpapi!ConvertInterfaceIndexToLuid
+iphlpapi!ConvertInterfaceLuidToAlias
+iphlpapi!ConvertInterfaceLuidToGuid
+iphlpapi!ConvertInterfaceLuidToIndex
+iphlpapi!ConvertInterfaceLuidToNameA
+iphlpapi!ConvertInterfaceLuidToNameW
+iphlpapi!ConvertInterfaceNameToLuidA
+iphlpapi!ConvertInterfaceNameToLuidW
+iphlpapi!ConvertInterfacePhysicalAddressToLuid
+iphlpapi!ConvertIpv4MaskToLength
+iphlpapi!ConvertLengthToIpv4Mask
+iphlpapi!ConvertRemoteInterfaceAliasToLuid
+iphlpapi!ConvertRemoteInterfaceGuidToLuid
+iphlpapi!ConvertRemoteInterfaceIndexToLuid
+iphlpapi!ConvertRemoteInterfaceLuidToAlias
+iphlpapi!ConvertRemoteInterfaceLuidToGuid
+iphlpapi!ConvertRemoteInterfaceLuidToIndex
+iphlpapi!ConvertStringToGuidA
+iphlpapi!ConvertStringToGuidW
+iphlpapi!ConvertStringToInterfacePhysicalAddress
+iphlpapi!CreateAnycastIpAddressEntry
+iphlpapi!CreateIpForwardEntry
+iphlpapi!CreateIpForwardEntry2
+iphlpapi!CreateIpNetEntry
+iphlpapi!CreateIpNetEntry2
+iphlpapi!CreatePersistentTcpPortReservation
+iphlpapi!CreatePersistentUdpPortReservation
+iphlpapi!CreateProxyArpEntry
+iphlpapi!CreateSortedAddressPairs
+iphlpapi!CreateUnicastIpAddressEntry
+iphlpapi!DeleteAnycastIpAddressEntry
+iphlpapi!DeleteIPAddress
+iphlpapi!DeleteIpForwardEntry
+iphlpapi!DeleteIpForwardEntry2
+iphlpapi!DeleteIpNetEntry
+iphlpapi!DeleteIpNetEntry2
+iphlpapi!DeletePersistentTcpPortReservation
+iphlpapi!DeletePersistentUdpPortReservation
+iphlpapi!DeleteProxyArpEntry
+iphlpapi!DeleteUnicastIpAddressEntry
+iphlpapi!DisableMediaSense
+iphlpapi!EnableRouter
+iphlpapi!FlushIpNetTable
+iphlpapi!FlushIpNetTable2
+iphlpapi!FlushIpPathTable
+iphlpapi!FreeMibTable
+iphlpapi!GetAdapterIndex
+iphlpapi!GetAdapterOrderMap
+iphlpapi!GetAdaptersAddresses
+iphlpapi!GetAdaptersInfo
+iphlpapi!GetAnycastIpAddressEntry
+iphlpapi!GetAnycastIpAddressTable
+iphlpapi!GetBestInterface
+iphlpapi!GetBestInterfaceEx
+iphlpapi!GetBestRoute
+iphlpapi!GetBestRoute2
+iphlpapi!GetCurrentThreadCompartmentId
+iphlpapi!GetExtendedTcpTable
+iphlpapi!GetExtendedUdpTable
+iphlpapi!GetFriendlyIfIndex
+iphlpapi!GetIcmpStatistics
+iphlpapi!GetIcmpStatisticsEx
+iphlpapi!GetIfEntry
+iphlpapi!GetIfEntry2
+iphlpapi!GetIfStackTable
+iphlpapi!GetIfTable
+iphlpapi!GetIfTable2
+iphlpapi!GetIfTable2Ex
+iphlpapi!GetInterfaceInfo
+iphlpapi!GetInvertedIfStackTable
+iphlpapi!GetIpAddrTable
+iphlpapi!GetIpErrorString
+iphlpapi!GetIpForwardEntry2
+iphlpapi!GetIpForwardTable
+iphlpapi!GetIpForwardTable2
+iphlpapi!GetIpInterfaceEntry
+iphlpapi!GetIpInterfaceTable
+iphlpapi!GetIpNetEntry2
+iphlpapi!GetIpNetTable
+iphlpapi!GetIpNetTable2
+iphlpapi!GetIpPathEntry
+iphlpapi!GetIpPathTable
+iphlpapi!GetIpStatistics
+iphlpapi!GetIpStatisticsEx
+iphlpapi!GetMulticastIpAddressEntry
+iphlpapi!GetMulticastIpAddressTable
+iphlpapi!GetNetworkInformation
+iphlpapi!GetNetworkParams
+iphlpapi!GetNumberOfInterfaces
+iphlpapi!GetOwnerModuleFromPidAndInfo
+iphlpapi!GetOwnerModuleFromTcp6Entry
+iphlpapi!GetOwnerModuleFromTcpEntry
+iphlpapi!GetOwnerModuleFromUdp6Entry
+iphlpapi!GetOwnerModuleFromUdpEntry
+iphlpapi!GetPerAdapterInfo
+iphlpapi!GetPerTcp6ConnectionEStats
+iphlpapi!GetPerTcp6ConnectionStats
+iphlpapi!GetPerTcpConnectionEStats
+iphlpapi!GetPerTcpConnectionStats
+iphlpapi!GetRTTAndHopCount
+iphlpapi!GetSessionCompartmentId
+iphlpapi!GetTcp6Table
+iphlpapi!GetTcp6Table2
+iphlpapi!GetTcpStatistics
+iphlpapi!GetTcpStatisticsEx
+iphlpapi!GetTcpTable
+iphlpapi!GetTcpTable2
+iphlpapi!GetTeredoPort
+iphlpapi!GetUdp6Table
+iphlpapi!GetUdpStatistics
+iphlpapi!GetUdpStatisticsEx
+iphlpapi!GetUdpTable
+iphlpapi!GetUnicastIpAddressEntry
+iphlpapi!GetUnicastIpAddressTable
+iphlpapi!GetUniDirectionalAdapterInfo
+iphlpapi!Icmp6CreateFile
+iphlpapi!Icmp6ParseReplies
+iphlpapi!Icmp6SendEcho2
+iphlpapi!IcmpCloseHandle
+iphlpapi!IcmpCreateFile
+iphlpapi!IcmpParseReplies
+iphlpapi!IcmpSendEcho
+iphlpapi!IcmpSendEcho2
+iphlpapi!IcmpSendEcho2Ex
+iphlpapi!if_indextoname
+iphlpapi!if_nametoindex
+iphlpapi!InitializeIpForwardEntry
+iphlpapi!InitializeIpInterfaceEntry
+iphlpapi!InitializeUnicastIpAddressEntry
+iphlpapi!InternalCleanupPersistentStore
+iphlpapi!InternalCreateAnycastIpAddressEntry
+iphlpapi!InternalCreateIpForwardEntry
+iphlpapi!InternalCreateIpForwardEntry2
+iphlpapi!InternalCreateIpNetEntry
+iphlpapi!InternalCreateIpNetEntry2
+iphlpapi!InternalCreateUnicastIpAddressEntry
+iphlpapi!InternalDeleteAnycastIpAddressEntry
+iphlpapi!InternalDeleteIpForwardEntry
+iphlpapi!InternalDeleteIpForwardEntry2
+iphlpapi!InternalDeleteIpNetEntry
+iphlpapi!InternalDeleteIpNetEntry2
+iphlpapi!InternalDeleteUnicastIpAddressEntry
+iphlpapi!InternalFindInterfaceByAddress
+iphlpapi!InternalGetAnycastIpAddressEntry
+iphlpapi!InternalGetAnycastIpAddressTable
+iphlpapi!InternalGetForwardIpTable2
+iphlpapi!InternalGetIfEntry2
+iphlpapi!InternalGetIfTable
+iphlpapi!InternalGetIfTable2
+iphlpapi!InternalGetIpAddrTable
+iphlpapi!InternalGetIpForwardEntry2
+iphlpapi!InternalGetIpForwardTable
+iphlpapi!InternalGetIpInterfaceEntry
+iphlpapi!InternalGetIpInterfaceTable
+iphlpapi!InternalGetIpNetEntry2
+iphlpapi!InternalGetIpNetTable
+iphlpapi!InternalGetIpNetTable2
+iphlpapi!InternalGetMulticastIpAddressEntry
+iphlpapi!InternalGetMulticastIpAddressTable
+iphlpapi!InternalGetTcp6Table2
+iphlpapi!InternalGetTcp6TableWithOwnerModule
+iphlpapi!InternalGetTcp6TableWithOwnerPid
+iphlpapi!InternalGetTcpTable
+iphlpapi!InternalGetTcpTable2
+iphlpapi!InternalGetTcpTableEx
+iphlpapi!InternalGetTcpTableWithOwnerModule
+iphlpapi!InternalGetTcpTableWithOwnerPid
+iphlpapi!InternalGetTunnelPhysicalAdapter
+iphlpapi!InternalGetUdp6TableWithOwnerModule
+iphlpapi!InternalGetUdp6TableWithOwnerPid
+iphlpapi!InternalGetUdpTable
+iphlpapi!InternalGetUdpTableEx
+iphlpapi!InternalGetUdpTableWithOwnerModule
+iphlpapi!InternalGetUdpTableWithOwnerPid
+iphlpapi!InternalGetUnicastIpAddressEntry
+iphlpapi!InternalGetUnicastIpAddressTable
+iphlpapi!InternalSetIfEntry
+iphlpapi!InternalSetIpForwardEntry
+iphlpapi!InternalSetIpForwardEntry2
+iphlpapi!InternalSetIpInterfaceEntry
+iphlpapi!InternalSetIpNetEntry
+iphlpapi!InternalSetIpNetEntry2
+iphlpapi!InternalSetIpStats
+iphlpapi!InternalSetTcpEntry
+iphlpapi!InternalSetTeredoPort
+iphlpapi!InternalSetUnicastIpAddressEntry
+iphlpapi!IpReleaseAddress
+iphlpapi!IpRenewAddress
+iphlpapi!LookupPersistentTcpPortReservation
+iphlpapi!LookupPersistentUdpPortReservation
+iphlpapi!NhGetGuidFromInterfaceName
+iphlpapi!NhGetInterfaceDescriptionFromGuid
+iphlpapi!NhGetInterfaceNameFromDeviceGuid
+iphlpapi!NhGetInterfaceNameFromGuid
+iphlpapi!NhpAllocateAndGetInterfaceInfoFromStack
+iphlpapi!NotifyAddrChange
+iphlpapi!NotifyIpInterfaceChange
+iphlpapi!NotifyRouteChange
+iphlpapi!NotifyRouteChange2
+iphlpapi!NotifyStableUnicastIpAddressTable
+iphlpapi!NotifyTeredoPortChange
+iphlpapi!NotifyUnicastIpAddressChange
+iphlpapi!NTPTimeToNTFileTime
+iphlpapi!NTTimeToNTPTime
+iphlpapi!ParseNetworkString
+iphlpapi!ResolveIpNetEntry2
+iphlpapi!ResolveNeighbor
+iphlpapi!RestoreMediaSense
+iphlpapi!SendARP
+iphlpapi!SetAdapterIpAddress
+iphlpapi!SetCurrentThreadCompartmentId
+iphlpapi!SetIfEntry
+iphlpapi!SetIpForwardEntry
+iphlpapi!SetIpForwardEntry2
+iphlpapi!SetIpInterfaceEntry
+iphlpapi!SetIpNetEntry
+iphlpapi!SetIpNetEntry2
+iphlpapi!SetIpStatistics
+iphlpapi!SetIpStatisticsEx
+iphlpapi!SetIpTTL
+iphlpapi!SetNetworkInformation
+iphlpapi!SetPerTcp6ConnectionEStats
+iphlpapi!SetPerTcp6ConnectionStats
+iphlpapi!SetPerTcpConnectionEStats
+iphlpapi!SetPerTcpConnectionStats
+iphlpapi!SetSessionCompartmentId
+iphlpapi!SetTcpEntry
+iphlpapi!SetUnicastIpAddressEntry
+iphlpapi!UnenableRouter
+kernel32!AcquireSRWLockExclusive
+kernel32!AcquireSRWLockShared
+kernel32!AddConsoleAliasA
+kernel32!AddConsoleAliasW
+kernel32!AddDllDirectory
+kernel32!AddSIDToBoundaryDescriptor
+kernel32!AddVectoredContinueHandler
+kernel32!AddVectoredExceptionHandler
+kernel32!AllocateUserPhysicalPages
+kernel32!AllocateUserPhysicalPagesNuma
+kernel32!AllocConsole
+kernel32!AreFileApisANSI
+kernel32!AttachConsole
+kernel32!Beep
+kernel32!CallbackMayRunLong
+kernel32!CallNamedPipeW
+kernel32!CancelIo
+kernel32!CancelIoEx
+kernel32!CancelSynchronousIo
+kernel32!CancelThreadpoolIo
+kernel32!CancelWaitableTimer
+kernel32!CheckRemoteDebuggerPresent
+kernel32!ClearCommBreak
+kernel32!ClearCommError
+kernel32!CloseHandle
+kernel32!ClosePrivateNamespace
+kernel32!CloseThreadpool
+kernel32!CloseThreadpoolCleanupGroup
+kernel32!CloseThreadpoolCleanupGroupMembers
+kernel32!CloseThreadpoolIo
+kernel32!CloseThreadpoolTimer
+kernel32!CloseThreadpoolWait
+kernel32!CloseThreadpoolWork
+kernel32!CompareFileTime
+kernel32!CompareStringEx
+kernel32!CompareStringOrdinal
+kernel32!CompareStringW
+kernel32!ConnectNamedPipe
+kernel32!ContinueDebugEvent
+kernel32!ConvertDefaultLocale
+kernel32!CopyContext
+kernel32!CopyFileExW
+kernel32!CopyFileW
+kernel32!CreateBoundaryDescriptorW
+kernel32!CreateConsoleScreenBuffer
+kernel32!CreateDirectoryA
+kernel32!CreateDirectoryExW
+kernel32!CreateDirectoryW
+kernel32!CreateEventA
+kernel32!CreateEventExA
+kernel32!CreateEventExW
+kernel32!CreateEventW
+kernel32!CreateFileA
+kernel32!CreateFileMappingNumaW
+kernel32!CreateFileMappingW
+kernel32!CreateFileW
+kernel32!CreateHardLinkA
+kernel32!CreateHardLinkW
+kernel32!CreateIoCompletionPort
+kernel32!CreateMemoryResourceNotification
+kernel32!CreateMutexA
+kernel32!CreateMutexExA
+kernel32!CreateMutexExW
+kernel32!CreateMutexW
+kernel32!CreateNamedPipeW
+kernel32!CreatePipe
+kernel32!CreatePrivateNamespaceW
+kernel32!CreateProcessA
+kernel32!CreateProcessW
+kernel32!CreateRemoteThread
+kernel32!CreateRemoteThreadEx
+kernel32!CreateSemaphoreExW
+kernel32!CreateSemaphoreW
+kernel32!CreateSymbolicLinkW
+kernel32!CreateThread
+kernel32!CreateThreadpool
+kernel32!CreateThreadpoolCleanupGroup
+kernel32!CreateThreadpoolIo
+kernel32!CreateThreadpoolTimer
+kernel32!CreateThreadpoolWait
+kernel32!CreateThreadpoolWork
+kernel32!CreateWaitableTimerExW
+kernel32!CreateWaitableTimerW
+kernel32!DebugActiveProcess
+kernel32!DebugActiveProcessStop
+kernel32!DebugBreak
+kernel32!DecodePointer
+kernel32!DecodeSystemPointer
+kernel32!DefineDosDeviceW
+kernel32!DelayLoadFailureHook
+kernel32!DeleteBoundaryDescriptor
+kernel32!DeleteCriticalSection
+kernel32!DeleteFileA
+kernel32!DeleteFileW
+kernel32!DeleteProcThreadAttributeList
+kernel32!DeleteVolumeMountPointW
+kernel32!DeviceIoControl
+kernel32!DisableThreadLibraryCalls
+kernel32!DisassociateCurrentThreadFromCallback
+kernel32!DisconnectNamedPipe
+kernel32!DuplicateHandle
+kernel32!EncodePointer
+kernel32!EncodeSystemPointer
+kernel32!EnterCriticalSection
+kernel32!EnumCalendarInfoExEx
+kernel32!EnumCalendarInfoExW
+kernel32!EnumCalendarInfoW
+kernel32!EnumDateFormatsExEx
+kernel32!EnumDateFormatsExW
+kernel32!EnumDateFormatsW
+kernel32!EnumResourceLanguagesExA
+kernel32!EnumResourceLanguagesExW
+kernel32!EnumResourceNamesExA
+kernel32!EnumResourceNamesExW
+kernel32!EnumResourceNamesW
+kernel32!EnumResourceTypesExA
+kernel32!EnumResourceTypesExW
+kernel32!EnumSystemCodePagesW
+kernel32!EnumSystemFirmwareTables
+kernel32!EnumSystemGeoID
+kernel32!EnumSystemLocalesA
+kernel32!EnumSystemLocalesEx
+kernel32!EnumSystemLocalesW
+kernel32!EnumTimeFormatsEx
+kernel32!EnumTimeFormatsW
+kernel32!EscapeCommFunction
+kernel32!ExitProcess
+kernel32!ExitThread
+kernel32!ExpandEnvironmentStringsA
+kernel32!ExpandEnvironmentStringsW
+kernel32!FatalAppExitA
+kernel32!FatalAppExitW
+kernel32!FileTimeToLocalFileTime
+kernel32!FileTimeToSystemTime
+kernel32!FillConsoleOutputAttribute
+kernel32!FillConsoleOutputCharacterA
+kernel32!FillConsoleOutputCharacterW
+kernel32!FindClose
+kernel32!FindCloseChangeNotification
+kernel32!FindFirstChangeNotificationA
+kernel32!FindFirstChangeNotificationW
+kernel32!FindFirstFileA
+kernel32!FindFirstFileExA
+kernel32!FindFirstFileExW
+kernel32!FindFirstFileNameW
+kernel32!FindFirstFileW
+kernel32!FindFirstStreamW
+kernel32!FindFirstVolumeW
+kernel32!FindNextChangeNotification
+kernel32!FindNextFileA
+kernel32!FindNextFileNameW
+kernel32!FindNextFileW
+kernel32!FindNextStreamW
+kernel32!FindNextVolumeW
+kernel32!FindNLSString
+kernel32!FindNLSStringEx
+kernel32!FindResourceExW
+kernel32!FindResourceW
+kernel32!FindStringOrdinal
+kernel32!FindVolumeClose
+kernel32!FlsAlloc
+kernel32!FlsFree
+kernel32!FlsGetValue
+kernel32!FlsSetValue
+kernel32!FlushConsoleInputBuffer
+kernel32!FlushFileBuffers
+kernel32!FlushInstructionCache
+kernel32!FlushProcessWriteBuffers
+kernel32!FlushViewOfFile
+kernel32!FoldStringW
+kernel32!FormatMessageA
+kernel32!FormatMessageW
+kernel32!FreeConsole
+kernel32!FreeEnvironmentStringsA
+kernel32!FreeEnvironmentStringsW
+kernel32!FreeLibrary
+kernel32!FreeLibraryAndExitThread
+kernel32!FreeLibraryWhenCallbackReturns
+kernel32!FreeResource
+kernel32!FreeUserPhysicalPages
+kernel32!GenerateConsoleCtrlEvent
+kernel32!GetACP
+kernel32!GetCalendarInfoEx
+kernel32!GetCalendarInfoW
+kernel32!GetCommandLineA
+kernel32!GetCommandLineW
+kernel32!GetCommConfig
+kernel32!GetCommMask
+kernel32!GetCommModemStatus
+kernel32!GetCommProperties
+kernel32!GetCommState
+kernel32!GetCommTimeouts
+kernel32!GetCompressedFileSizeA
+kernel32!GetCompressedFileSizeW
+kernel32!GetComputerNameExA
+kernel32!GetComputerNameExW
+kernel32!GetConsoleAliasA
+kernel32!GetConsoleAliasesA
+kernel32!GetConsoleAliasesLengthA
+kernel32!GetConsoleAliasesLengthW
+kernel32!GetConsoleAliasesW
+kernel32!GetConsoleAliasExesA
+kernel32!GetConsoleAliasExesLengthA
+kernel32!GetConsoleAliasExesLengthW
+kernel32!GetConsoleAliasExesW
+kernel32!GetConsoleAliasW
+kernel32!GetConsoleCP
+kernel32!GetConsoleCursorInfo
+kernel32!GetConsoleDisplayMode
+kernel32!GetConsoleFontSize
+kernel32!GetConsoleHistoryInfo
+kernel32!GetConsoleMode
+kernel32!GetConsoleOriginalTitleA
+kernel32!GetConsoleOriginalTitleW
+kernel32!GetConsoleOutputCP
+kernel32!GetConsoleProcessList
+kernel32!GetConsoleScreenBufferInfo
+kernel32!GetConsoleScreenBufferInfoEx
+kernel32!GetConsoleSelectionInfo
+kernel32!GetConsoleTitleA
+kernel32!GetConsoleTitleW
+kernel32!GetConsoleWindow
+kernel32!GetCPInfo
+kernel32!GetCPInfoExW
+kernel32!GetCurrencyFormatEx
+kernel32!GetCurrencyFormatW
+kernel32!GetCurrentConsoleFont
+kernel32!GetCurrentConsoleFontEx
+kernel32!GetCurrentDirectoryA
+kernel32!GetCurrentDirectoryW
+kernel32!GetCurrentProcess
+kernel32!GetCurrentProcessId
+kernel32!GetCurrentProcessorNumber
+kernel32!GetCurrentProcessorNumberEx
+kernel32!GetCurrentThread
+kernel32!GetCurrentThreadId
+kernel32!GetDateFormatA
+kernel32!GetDateFormatEx
+kernel32!GetDateFormatW
+kernel32!GetDiskFreeSpaceA
+kernel32!GetDiskFreeSpaceExA
+kernel32!GetDiskFreeSpaceExW
+kernel32!GetDiskFreeSpaceW
+kernel32!GetDriveTypeA
+kernel32!GetDriveTypeW
+kernel32!GetDurationFormatEx
+kernel32!GetDynamicTimeZoneInformation
+kernel32!GetEnvironmentStrings
+kernel32!GetEnvironmentStringsW
+kernel32!GetEnvironmentVariableA
+kernel32!GetEnvironmentVariableW
+kernel32!GetErrorMode
+kernel32!GetExitCodeProcess
+kernel32!GetExitCodeThread
+kernel32!GetFileAttributesA
+kernel32!GetFileAttributesExA
+kernel32!GetFileAttributesExW
+kernel32!GetFileAttributesW
+kernel32!GetFileInformationByHandle
+kernel32!GetFileInformationByHandleEx
+kernel32!GetFileMUIInfo
+kernel32!GetFileMUIPath
+kernel32!GetFileSize
+kernel32!GetFileSizeEx
+kernel32!GetFileTime
+kernel32!GetFileType
+kernel32!GetFinalPathNameByHandleA
+kernel32!GetFinalPathNameByHandleW
+kernel32!GetFirmwareEnvironmentVariableA
+kernel32!GetFirmwareEnvironmentVariableW
+kernel32!GetFullPathNameA
+kernel32!GetFullPathNameW
+kernel32!GetGeoInfoW
+kernel32!GetHandleInformation
+kernel32!GetLargePageMinimum
+kernel32!GetLargestConsoleWindowSize
+kernel32!GetLastError
+kernel32!GetLocaleInfoA
+kernel32!GetLocaleInfoEx
+kernel32!GetLocaleInfoW
+kernel32!GetLocalTime
+kernel32!GetLogicalDrives
+kernel32!GetLogicalDriveStringsW
+kernel32!GetLogicalProcessorInformation
+kernel32!GetLogicalProcessorInformationEx
+kernel32!GetLongPathNameA
+kernel32!GetLongPathNameW
+kernel32!GetModuleFileNameA
+kernel32!GetModuleFileNameW
+kernel32!GetModuleHandleA
+kernel32!GetModuleHandleExA
+kernel32!GetModuleHandleExW
+kernel32!GetModuleHandleW
+kernel32!GetNamedPipeClientComputerNameW
+kernel32!GetNamedPipeHandleStateW
+kernel32!GetNamedPipeInfo
+kernel32!GetNativeSystemInfo
+kernel32!GetNLSVersion
+kernel32!GetNLSVersionEx
+kernel32!GetNumaHighestNodeNumber
+kernel32!GetNumaNodeProcessorMaskEx
+kernel32!GetNumaProximityNodeEx
+kernel32!GetNumberFormatEx
+kernel32!GetNumberOfConsoleInputEvents
+kernel32!GetNumberOfConsoleMouseButtons
+kernel32!GetOEMCP
+kernel32!GetOverlappedResult
+kernel32!GetPhysicallyInstalledSystemMemory
+kernel32!GetPriorityClass
+kernel32!GetProcAddress
+kernel32!GetProcessGroupAffinity
+kernel32!GetProcessHandleCount
+kernel32!GetProcessHeap
+kernel32!GetProcessHeaps
+kernel32!GetProcessId
+kernel32!GetProcessIdOfThread
+kernel32!GetProcessorSystemCycleTime
+kernel32!GetProcessPreferredUILanguages
+kernel32!GetProcessPriorityBoost
+kernel32!GetProcessShutdownParameters
+kernel32!GetProcessTimes
+kernel32!GetProcessVersion
+kernel32!GetProcessWorkingSetSizeEx
+kernel32!GetProductInfo
+kernel32!GetQueuedCompletionStatus
+kernel32!GetQueuedCompletionStatusEx
+kernel32!GetShortPathNameW
+kernel32!GetStartupInfoW
+kernel32!GetStdHandle
+kernel32!GetStringTypeExW
+kernel32!GetStringTypeW
+kernel32!GetSystemDefaultLangID
+kernel32!GetSystemDefaultLCID
+kernel32!GetSystemDefaultLocaleName
+kernel32!GetSystemDirectoryA
+kernel32!GetSystemDirectoryW
+kernel32!GetSystemFileCacheSize
+kernel32!GetSystemFirmwareTable
+kernel32!GetSystemInfo
+kernel32!GetSystemPreferredUILanguages
+kernel32!GetSystemTime
+kernel32!GetSystemTimeAdjustment
+kernel32!GetSystemTimeAsFileTime
+kernel32!GetSystemTimes
+kernel32!GetSystemWindowsDirectoryA
+kernel32!GetSystemWindowsDirectoryW
+kernel32!GetSystemWow64DirectoryA
+kernel32!GetSystemWow64DirectoryW
+kernel32!GetTempFileNameA
+kernel32!GetTempFileNameW
+kernel32!GetTempPathA
+kernel32!GetTempPathW
+kernel32!GetThreadContext
+kernel32!GetThreadErrorMode
+kernel32!GetThreadGroupAffinity
+kernel32!GetThreadId
+kernel32!GetThreadIdealProcessorEx
+kernel32!GetThreadIOPendingFlag
+kernel32!GetThreadLocale
+kernel32!GetThreadPreferredUILanguages
+kernel32!GetThreadPriority
+kernel32!GetThreadPriorityBoost
+kernel32!GetThreadTimes
+kernel32!GetThreadUILanguage
+kernel32!GetTickCount
+kernel32!GetTickCount64
+kernel32!GetTimeFormatA
+kernel32!GetTimeFormatEx
+kernel32!GetTimeFormatW
+kernel32!GetTimeZoneInformation
+kernel32!GetTimeZoneInformationForYear
+kernel32!GetUILanguageInfo
+kernel32!GetUserDefaultLangID
+kernel32!GetUserDefaultLCID
+kernel32!GetUserDefaultLocaleName
+kernel32!GetUserGeoID
+kernel32!GetUserPreferredUILanguages
+kernel32!GetVersion
+kernel32!GetVersionExA
+kernel32!GetVersionExW
+kernel32!GetVolumeInformationA
+kernel32!GetVolumeInformationByHandleW
+kernel32!GetVolumeInformationW
+kernel32!GetVolumeNameForVolumeMountPointW
+kernel32!GetVolumePathNamesForVolumeNameW
+kernel32!GetVolumePathNameW
+kernel32!GetWindowsDirectoryA
+kernel32!GetWindowsDirectoryW
+kernel32!GetWriteWatch
+kernel32!GlobalAlloc
+kernel32!GlobalFree
+kernel32!GlobalMemoryStatusEx
+kernel32!HeapAlloc
+kernel32!HeapCompact
+kernel32!HeapCreate
+kernel32!HeapDestroy
+kernel32!HeapFree
+kernel32!HeapLock
+kernel32!HeapQueryInformation
+kernel32!HeapReAlloc
+kernel32!HeapSetInformation
+kernel32!HeapSize
+kernel32!HeapUnlock
+kernel32!HeapValidate
+kernel32!HeapWalk
+kernel32!IdnToAscii
+kernel32!IdnToUnicode
+kernel32!InitializeConditionVariable
+kernel32!InitializeContext
+kernel32!InitializeCriticalSection
+kernel32!InitializeCriticalSectionAndSpinCount
+kernel32!InitializeCriticalSectionEx
+kernel32!InitializeProcThreadAttributeList
+kernel32!InitializeSListHead
+kernel32!InitializeSRWLock
+kernel32!InitOnceBeginInitialize
+kernel32!InitOnceComplete
+kernel32!InitOnceExecuteOnce
+kernel32!InitOnceInitialize
+kernel32!InterlockedFlushSList
+kernel32!InterlockedPopEntrySList
+kernel32!InterlockedPushEntrySList
+kernel32!IsDBCSLeadByte
+kernel32!IsDBCSLeadByteEx
+kernel32!IsDebuggerPresent
+kernel32!IsNLSDefinedString
+kernel32!IsProcessInJob
+kernel32!IsProcessorFeaturePresent
+kernel32!IsThreadAFiber
+kernel32!IsThreadpoolTimerSet
+kernel32!IsValidCodePage
+kernel32!IsValidLanguageGroup
+kernel32!IsValidLocale
+kernel32!IsValidLocaleName
+kernel32!IsWow64Process
+kernel32!K32EmptyWorkingSet
+kernel32!K32EnumDeviceDrivers
+kernel32!K32EnumPageFilesW
+kernel32!K32EnumProcesses
+kernel32!K32EnumProcessModules
+kernel32!K32EnumProcessModulesEx
+kernel32!K32GetDeviceDriverBaseNameW
+kernel32!K32GetDeviceDriverFileNameW
+kernel32!K32GetMappedFileNameW
+kernel32!K32GetModuleBaseNameW
+kernel32!K32GetModuleFileNameExW
+kernel32!K32GetModuleInformation
+kernel32!K32GetPerformanceInfo
+kernel32!K32GetProcessImageFileNameW
+kernel32!K32GetProcessMemoryInfo
+kernel32!K32GetWsChanges
+kernel32!K32GetWsChangesEx
+kernel32!K32InitializeProcessForWsWatch
+kernel32!K32QueryWorkingSet
+kernel32!K32QueryWorkingSetEx
+kernel32!LCIDToLocaleName
+kernel32!LCMapStringA
+kernel32!LCMapStringEx
+kernel32!LCMapStringW
+kernel32!LeaveCriticalSection
+kernel32!LeaveCriticalSectionWhenCallbackReturns
+kernel32!LoadLibraryA
+kernel32!LoadLibraryExA
+kernel32!LoadLibraryExW
+kernel32!LoadLibraryW
+kernel32!LoadResource
+kernel32!LocalAlloc
+kernel32!LocaleNameToLCID
+kernel32!LocalFileTimeToFileTime
+kernel32!LocalFree
+kernel32!LocalLock
+kernel32!LocalReAlloc
+kernel32!LocalUnlock
+kernel32!LockFile
+kernel32!LockFileEx
+kernel32!LockResource
+kernel32!MapUserPhysicalPages
+kernel32!MapViewOfFile
+kernel32!MapViewOfFileEx
+kernel32!MoveFileExW
+kernel32!MoveFileWithProgressW
+kernel32!MultiByteToWideChar
+kernel32!NeedCurrentDirectoryForExePathA
+kernel32!NeedCurrentDirectoryForExePathW
+kernel32!OpenEventA
+kernel32!OpenEventW
+kernel32!OpenFileById
+kernel32!OpenFileMappingW
+kernel32!OpenMutexW
+kernel32!OpenPrivateNamespaceW
+kernel32!OpenProcess
+kernel32!OpenSemaphoreW
+kernel32!OpenThread
+kernel32!OpenWaitableTimerW
+kernel32!OutputDebugStringA
+kernel32!OutputDebugStringW
+kernel32!PeekConsoleInputA
+kernel32!PeekConsoleInputW
+kernel32!PeekNamedPipe
+kernel32!PostQueuedCompletionStatus
+kernel32!ProcessIdToSessionId
+kernel32!PurgeComm
+kernel32!QueryDepthSList
+kernel32!QueryDosDeviceW
+kernel32!QueryFullProcessImageNameW
+kernel32!QueryIdleProcessorCycleTime
+kernel32!QueryIdleProcessorCycleTimeEx
+kernel32!QueryMemoryResourceNotification
+kernel32!QueryPerformanceCounter
+kernel32!QueryPerformanceFrequency
+kernel32!QueryProcessAffinityUpdateMode
+kernel32!QueryProcessCycleTime
+kernel32!QueryThreadCycleTime
+kernel32!QueryThreadpoolStackInformation
+kernel32!QueryUnbiasedInterruptTime
+kernel32!QueueUserAPC
+kernel32!RaiseException
+kernel32!RaiseFailFastException
+kernel32!ReadConsoleA
+kernel32!ReadConsoleInputA
+kernel32!ReadConsoleInputW
+kernel32!ReadConsoleOutputA
+kernel32!ReadConsoleOutputAttribute
+kernel32!ReadConsoleOutputCharacterA
+kernel32!ReadConsoleOutputCharacterW
+kernel32!ReadConsoleOutputW
+kernel32!ReadConsoleW
+kernel32!ReadDirectoryChangesW
+kernel32!ReadFile
+kernel32!ReadFileEx
+kernel32!ReadFileScatter
+kernel32!ReadProcessMemory
+kernel32!ReleaseMutex
+kernel32!ReleaseMutexWhenCallbackReturns
+kernel32!ReleaseSemaphore
+kernel32!ReleaseSemaphoreWhenCallbackReturns
+kernel32!ReleaseSRWLockExclusive
+kernel32!ReleaseSRWLockShared
+kernel32!RemoveDirectoryA
+kernel32!RemoveDirectoryW
+kernel32!RemoveDllDirectory
+kernel32!RemoveVectoredContinueHandler
+kernel32!RemoveVectoredExceptionHandler
+kernel32!ReOpenFile
+kernel32!ReplaceFileW
+kernel32!ResetEvent
+kernel32!ResetWriteWatch
+kernel32!ResolveLocaleName
+kernel32!RestoreLastError
+kernel32!ResumeThread
+kernel32!RtlCaptureContext
+kernel32!RtlCaptureStackBackTrace
+kernel32!RtlUnwind
+kernel32!ScrollConsoleScreenBufferA
+kernel32!ScrollConsoleScreenBufferW
+kernel32!SearchPathA
+kernel32!SearchPathW
+kernel32!SetCalendarInfoW
+kernel32!SetCommBreak
+kernel32!SetCommConfig
+kernel32!SetCommMask
+kernel32!SetCommState
+kernel32!SetCommTimeouts
+kernel32!SetComputerNameA
+kernel32!SetComputerNameExA
+kernel32!SetComputerNameExW
+kernel32!SetComputerNameW
+kernel32!SetConsoleActiveScreenBuffer
+kernel32!SetConsoleCP
+kernel32!SetConsoleCtrlHandler
+kernel32!SetConsoleCursorInfo
+kernel32!SetConsoleCursorPosition
+kernel32!SetConsoleDisplayMode
+kernel32!SetConsoleHistoryInfo
+kernel32!SetConsoleMode
+kernel32!SetConsoleOutputCP
+kernel32!SetConsoleScreenBufferInfoEx
+kernel32!SetConsoleScreenBufferSize
+kernel32!SetConsoleTextAttribute
+kernel32!SetConsoleTitleA
+kernel32!SetConsoleTitleW
+kernel32!SetConsoleWindowInfo
+kernel32!SetCriticalSectionSpinCount
+kernel32!SetCurrentConsoleFontEx
+kernel32!SetCurrentDirectoryA
+kernel32!SetCurrentDirectoryW
+kernel32!SetDefaultDllDirectories
+kernel32!SetDynamicTimeZoneInformation
+kernel32!SetEndOfFile
+kernel32!SetEnvironmentStringsW
+kernel32!SetEnvironmentVariableA
+kernel32!SetEnvironmentVariableW
+kernel32!SetErrorMode
+kernel32!SetEvent
+kernel32!SetEventWhenCallbackReturns
+kernel32!SetFileApisToANSI
+kernel32!SetFileApisToOEM
+kernel32!SetFileAttributesA
+kernel32!SetFileAttributesW
+kernel32!SetFileInformationByHandle
+kernel32!SetFileIoOverlappedRange
+kernel32!SetFilePointer
+kernel32!SetFilePointerEx
+kernel32!SetFileTime
+kernel32!SetFileValidData
+kernel32!SetFirmwareEnvironmentVariableA
+kernel32!SetFirmwareEnvironmentVariableW
+kernel32!SetHandleInformation
+kernel32!SetLastError
+kernel32!SetLocaleInfoW
+kernel32!SetLocalTime
+kernel32!SetNamedPipeHandleState
+kernel32!SetPriorityClass
+kernel32!SetProcessAffinityUpdateMode
+kernel32!SetProcessPreferredUILanguages
+kernel32!SetProcessPriorityBoost
+kernel32!SetProcessShutdownParameters
+kernel32!SetProcessWorkingSetSizeEx
+kernel32!SetStdHandle
+kernel32!SetStdHandleEx
+kernel32!SetSystemFileCacheSize
+kernel32!SetSystemTime
+kernel32!SetSystemTimeAdjustment
+kernel32!SetThreadContext
+kernel32!SetThreadErrorMode
+kernel32!SetThreadGroupAffinity
+kernel32!SetThreadIdealProcessor
+kernel32!SetThreadIdealProcessorEx
+kernel32!SetThreadLocale
+kernel32!SetThreadpoolStackInformation
+kernel32!SetThreadpoolThreadMaximum
+kernel32!SetThreadpoolThreadMinimum
+kernel32!SetThreadpoolTimer
+kernel32!SetThreadpoolWait
+kernel32!SetThreadPreferredUILanguages
+kernel32!SetThreadPriority
+kernel32!SetThreadPriorityBoost
+kernel32!SetThreadStackGuarantee
+kernel32!SetThreadUILanguage
+kernel32!SetTimeZoneInformation
+kernel32!SetUnhandledExceptionFilter
+kernel32!SetupComm
+kernel32!SetUserGeoID
+kernel32!SetWaitableTimer
+kernel32!SetWaitableTimerEx
+kernel32!SignalObjectAndWait
+kernel32!SizeofResource
+kernel32!Sleep
+kernel32!SleepConditionVariableCS
+kernel32!SleepConditionVariableSRW
+kernel32!SleepEx
+kernel32!StartThreadpoolIo
+kernel32!SubmitThreadpoolWork
+kernel32!SuspendThread
+kernel32!SwitchToThread
+kernel32!SystemTimeToFileTime
+kernel32!SystemTimeToTzSpecificLocalTime
+kernel32!SystemTimeToTzSpecificLocalTimeEx
+kernel32!TerminateProcess
+kernel32!TerminateThread
+kernel32!TlsAlloc
+kernel32!TlsFree
+kernel32!TlsGetValue
+kernel32!TlsSetValue
+kernel32!TransactNamedPipe
+kernel32!TransmitCommChar
+kernel32!TryAcquireSRWLockExclusive
+kernel32!TryAcquireSRWLockShared
+kernel32!TryEnterCriticalSection
+kernel32!TrySubmitThreadpoolCallback
+kernel32!TzSpecificLocalTimeToSystemTime
+kernel32!TzSpecificLocalTimeToSystemTimeEx
+kernel32!UnhandledExceptionFilter
+kernel32!UnlockFile
+kernel32!UnlockFileEx
+kernel32!UnmapViewOfFile
+kernel32!UpdateProcThreadAttribute
+kernel32!VerSetConditionMask
+kernel32!VirtualAlloc
+kernel32!VirtualAllocEx
+kernel32!VirtualAllocExNuma
+kernel32!VirtualFree
+kernel32!VirtualFreeEx
+kernel32!VirtualLock
+kernel32!VirtualProtect
+kernel32!VirtualProtectEx
+kernel32!VirtualQuery
+kernel32!VirtualQueryEx
+kernel32!VirtualUnlock
+kernel32!WaitCommEvent
+kernel32!WaitForDebugEvent
+kernel32!WaitForMultipleObjects
+kernel32!WaitForMultipleObjectsEx
+kernel32!WaitForSingleObject
+kernel32!WaitForSingleObjectEx
+kernel32!WaitForThreadpoolIoCallbacks
+kernel32!WaitForThreadpoolTimerCallbacks
+kernel32!WaitForThreadpoolWaitCallbacks
+kernel32!WaitForThreadpoolWorkCallbacks
+kernel32!WaitNamedPipeW
+kernel32!WakeAllConditionVariable
+kernel32!WakeConditionVariable
+kernel32!WideCharToMultiByte
+kernel32!Wow64DisableWow64FsRedirection
+kernel32!Wow64RevertWow64FsRedirection
+kernel32!WriteConsoleA
+kernel32!WriteConsoleInputA
+kernel32!WriteConsoleInputW
+kernel32!WriteConsoleOutputA
+kernel32!WriteConsoleOutputAttribute
+kernel32!WriteConsoleOutputCharacterA
+kernel32!WriteConsoleOutputCharacterW
+kernel32!WriteConsoleOutputW
+kernel32!WriteConsoleW
+kernel32!WriteFile
+kernel32!WriteFileEx
+kernel32!WriteFileGather
+kernel32!WriteProcessMemory
+mswsock!AcceptEx
+mswsock!dn_expand
+mswsock!EnumProtocolsA
+mswsock!EnumProtocolsW
+mswsock!GetAcceptExSockaddrs
+mswsock!GetAddressByNameA
+mswsock!GetAddressByNameW
+mswsock!GetNameByTypeA
+mswsock!GetNameByTypeW
+mswsock!getnetbyname
+mswsock!GetServiceA
+mswsock!GetServiceW
+mswsock!GetTypeByNameA
+mswsock!GetTypeByNameW
+mswsock!inet_network
+mswsock!MigrateWinsockConfiguration
+mswsock!NPLoadNameSpaces
+mswsock!rcmd
+mswsock!rexec
+mswsock!rresvport
+mswsock!s_perror
+mswsock!sethostname
+mswsock!SetServiceA
+mswsock!SetServiceW
+mswsock!TransmitFile
+mswsock!WSARecvEx
+ncrypt!GetIsolationServerInterface
+ncrypt!GetKeyStorageInterface
+ncrypt!GetSChannelInterface
+ncrypt!NCryptCreatePersistedKey
+ncrypt!NCryptDecrypt
+ncrypt!NCryptDeleteKey
+ncrypt!NCryptDeriveKey
+ncrypt!NCryptEncrypt
+ncrypt!NCryptEnumAlgorithms
+ncrypt!NCryptEnumKeys
+ncrypt!NCryptEnumStorageProviders
+ncrypt!NCryptExportKey
+ncrypt!NCryptFinalizeKey
+ncrypt!NCryptFreeBuffer
+ncrypt!NCryptFreeObject
+ncrypt!NCryptGetProperty
+ncrypt!NCryptImportKey
+ncrypt!NCryptIsAlgSupported
+ncrypt!NCryptIsKeyHandle
+ncrypt!NCryptNotifyChangeKey
+ncrypt!NCryptOpenKey
+ncrypt!NCryptOpenStorageProvider
+ncrypt!NCryptSecretAgreement
+ncrypt!NCryptSetAuditingInterface
+ncrypt!NCryptSetProperty
+ncrypt!NCryptSignHash
+ncrypt!NCryptTranslateHandle
+ncrypt!NCryptVerifySignature
+ncrypt!SslChangeNotify
+ncrypt!SslComputeClientAuthHash
+ncrypt!SslComputeEapKeyBlock
+ncrypt!SslComputeFinishedHash
+ncrypt!SslComputeSessionHash
+ncrypt!SslCreateClientAuthHash
+ncrypt!SslCreateEphemeralKey
+ncrypt!SslCreateHandshakeHash
+ncrypt!SslDecrementProviderReferenceCount
+ncrypt!SslDecryptPacket
+ncrypt!SslEncryptPacket
+ncrypt!SslEnumCipherSuites
+ncrypt!SslEnumProtocolProviders
+ncrypt!SslExportKey
+ncrypt!SslFreeBuffer
+ncrypt!SslFreeObject
+ncrypt!SslGenerateMasterKey
+ncrypt!SslGeneratePreMasterKey
+ncrypt!SslGenerateSessionKeys
+ncrypt!SslGetCipherSuitePRFHashAlgorithm
+ncrypt!SslGetKeyProperty
+ncrypt!SslGetProviderProperty
+ncrypt!SslHashHandshake
+ncrypt!SslImportKey
+ncrypt!SslImportMasterKey
+ncrypt!SslIncrementProviderReferenceCount
+ncrypt!SslLookupCipherLengths
+ncrypt!SslLookupCipherSuiteInfo
+ncrypt!SslOpenPrivateKey
+ncrypt!SslOpenProvider
+ncrypt!SslSignHash
+ncrypt!SslVerifySignature
+ntdll!RtlCopyContext
+ntdll!RtlCopyExtendedContext
+ntdll!RtlGetEnabledExtendedFeatures
+ntdll!RtlGetExtendedContextLength
+ntdll!RtlGetExtendedFeaturesMask
+ntdll!RtlInitializeExtendedContext
+ntdll!RtlLocateExtendedFeature
+ntdll!RtlLocateLegacyContext
+ntdll!RtlSetExtendedFeaturesMask
+ole32!CLSIDFromProgID
+ole32!CLSIDFromProgIDEx
+ole32!CLSIDFromString
+ole32!CoAddRefServerProcess
+ole32!CoCancelCall
+ole32!CoCopyProxy
+ole32!CoCreateFreeThreadedMarshaler
+ole32!CoCreateGuid
+ole32!CoCreateInstance
+ole32!CoCreateInstanceEx
+ole32!CoDisableCallCancellation
+ole32!CoDisconnectContext
+ole32!CoDisconnectObject
+ole32!CoEnableCallCancellation
+ole32!CoFileTimeNow
+ole32!CoFreeUnusedLibraries
+ole32!CoFreeUnusedLibrariesEx
+ole32!CoGetApartmentType
+ole32!CoGetCallContext
+ole32!CoGetCallerTID
+ole32!CoGetCancelObject
+ole32!CoGetClassObject
+ole32!CoGetContextToken
+ole32!CoGetCurrentLogicalThreadId
+ole32!CoGetCurrentProcess
+ole32!CoGetDefaultContext
+ole32!CoGetInterfaceAndReleaseStream
+ole32!CoGetMalloc
+ole32!CoGetMarshalSizeMax
+ole32!CoGetObjectContext
+ole32!CoGetPSClsid
+ole32!CoGetStandardMarshal
+ole32!CoGetStdMarshalEx
+ole32!CoGetTreatAsClass
+ole32!CoImpersonateClient
+ole32!CoInitializeEx
+ole32!CoInitializeSecurity
+ole32!CoInvalidateRemoteMachineBindings
+ole32!CoIsHandlerConnected
+ole32!CoLockObjectExternal
+ole32!CoMarshalHresult
+ole32!CoMarshalInterface
+ole32!CoMarshalInterThreadInterfaceInStream
+ole32!CoQueryAuthenticationServices
+ole32!CoQueryClientBlanket
+ole32!CoQueryProxyBlanket
+ole32!CoRegisterActivationFilter
+ole32!CoRegisterClassObject
+ole32!CoRegisterPSClsid
+ole32!CoRegisterSurrogate
+ole32!CoReleaseMarshalData
+ole32!CoReleaseServerProcess
+ole32!CoResumeClassObjects
+ole32!CoRevertToSelf
+ole32!CoRevokeClassObject
+ole32!CoSetCancelObject
+ole32!CoSetProxyBlanket
+ole32!CoSuspendClassObjects
+ole32!CoSwitchCallContext
+ole32!CoTaskMemAlloc
+ole32!CoTaskMemFree
+ole32!CoTaskMemRealloc
+ole32!CoTestCancel
+ole32!CoUninitialize
+ole32!CoUnmarshalHresult
+ole32!CoUnmarshalInterface
+ole32!CoWaitForMultipleHandles
+ole32!CreateStreamOnHGlobal
+ole32!FreePropVariantArray
+ole32!GetHGlobalFromStream
+ole32!IIDFromString
+ole32!ProgIDFromCLSID
+ole32!PropVariantClear
+ole32!PropVariantCopy
+ole32!StringFromCLSID
+ole32!StringFromGUID2
+ole32!StringFromIID
+oleaut32!BSTR_UserFree
+oleaut32!BSTR_UserMarshal
+oleaut32!BSTR_UserSize
+oleaut32!BSTR_UserUnmarshal
+oleaut32!BstrFromVector
+oleaut32!ClearCustData
+oleaut32!CreateDispTypeInfo
+oleaut32!CreateErrorInfo
+oleaut32!CreateStdDispatch
+oleaut32!CreateTypeLib
+oleaut32!CreateTypeLib2
+oleaut32!DispCallFunc
+oleaut32!DispGetIDsOfNames
+oleaut32!DispGetParam
+oleaut32!DispInvoke
+oleaut32!DosDateTimeToVariantTime
+oleaut32!GetActiveObject
+oleaut32!GetAltMonthNames
+oleaut32!GetErrorInfo
+oleaut32!GetRecordInfoFromGuids
+oleaut32!GetRecordInfoFromTypeInfo
+oleaut32!GetVarConversionLocaleSetting
+oleaut32!LHashValOfNameSys
+oleaut32!LHashValOfNameSysA
+oleaut32!LoadRegTypeLib
+oleaut32!LoadTypeLib
+oleaut32!LoadTypeLibEx
+oleaut32!LPSAFEARRAY_Marshal
+oleaut32!LPSAFEARRAY_Size
+oleaut32!LPSAFEARRAY_Unmarshal
+oleaut32!LPSAFEARRAY_UserFree
+oleaut32!LPSAFEARRAY_UserMarshal
+oleaut32!LPSAFEARRAY_UserSize
+oleaut32!LPSAFEARRAY_UserUnmarshal
+oleaut32!OaBuildVersion
+oleaut32!OACreateTypeLib2
+oleaut32!OaEnablePerUserTLibRegistration
+oleaut32!OleCreateFontIndirect
+oleaut32!OleCreatePictureIndirect
+oleaut32!OleCreatePropertyFrame
+oleaut32!OleCreatePropertyFrameIndirect
+oleaut32!OleIconToCursor
+oleaut32!OleLoadPicture
+oleaut32!OleLoadPictureEx
+oleaut32!OleLoadPictureFile
+oleaut32!OleLoadPictureFileEx
+oleaut32!OleLoadPicturePath
+oleaut32!OleSavePictureFile
+oleaut32!OleTranslateColor
+oleaut32!QueryPathOfRegTypeLib
+oleaut32!RegisterActiveObject
+oleaut32!RegisterTypeLib
+oleaut32!RegisterTypeLibForUser
+oleaut32!RevokeActiveObject
+oleaut32!SafeArrayAccessData
+oleaut32!SafeArrayAddRef
+oleaut32!SafeArrayAllocData
+oleaut32!SafeArrayAllocDescriptor
+oleaut32!SafeArrayAllocDescriptorEx
+oleaut32!SafeArrayCopy
+oleaut32!SafeArrayCopyData
+oleaut32!SafeArrayCreate
+oleaut32!SafeArrayCreateEx
+oleaut32!SafeArrayCreateVector
+oleaut32!SafeArrayCreateVectorEx
+oleaut32!SafeArrayDestroy
+oleaut32!SafeArrayDestroyData
+oleaut32!SafeArrayDestroyDescriptor
+oleaut32!SafeArrayGetDim
+oleaut32!SafeArrayGetElement
+oleaut32!SafeArrayGetElemsize
+oleaut32!SafeArrayGetIID
+oleaut32!SafeArrayGetLBound
+oleaut32!SafeArrayGetRecordInfo
+oleaut32!SafeArrayGetUBound
+oleaut32!SafeArrayGetVartype
+oleaut32!SafeArrayLock
+oleaut32!SafeArrayPtrOfIndex
+oleaut32!SafeArrayPutElement
+oleaut32!SafeArrayRedim
+oleaut32!SafeArrayReleaseData
+oleaut32!SafeArrayReleaseDescriptor
+oleaut32!SafeArraySetIID
+oleaut32!SafeArraySetRecordInfo
+oleaut32!SafeArrayUnaccessData
+oleaut32!SafeArrayUnlock
+oleaut32!SetErrorInfo
+oleaut32!SetOaNoCache
+oleaut32!SetVarConversionLocaleSetting
+oleaut32!SysAddRefString
+oleaut32!SysAllocString
+oleaut32!SysAllocStringByteLen
+oleaut32!SysAllocStringLen
+oleaut32!SysFreeString
+oleaut32!SysReAllocString
+oleaut32!SysReAllocStringLen
+oleaut32!SysReleaseString
+oleaut32!SysStringByteLen
+oleaut32!SysStringLen
+oleaut32!SystemTimeToVariantTime
+oleaut32!UnRegisterTypeLib
+oleaut32!UnRegisterTypeLibForUser
+oleaut32!VarAbs
+oleaut32!VarAdd
+oleaut32!VarAnd
+oleaut32!VarBoolFromCy
+oleaut32!VarBoolFromDate
+oleaut32!VarBoolFromDec
+oleaut32!VarBoolFromDisp
+oleaut32!VarBoolFromI1
+oleaut32!VarBoolFromI2
+oleaut32!VarBoolFromI4
+oleaut32!VarBoolFromI8
+oleaut32!VarBoolFromR4
+oleaut32!VarBoolFromR8
+oleaut32!VarBoolFromStr
+oleaut32!VarBoolFromUI1
+oleaut32!VarBoolFromUI2
+oleaut32!VarBoolFromUI4
+oleaut32!VarBoolFromUI8
+oleaut32!VarBstrCat
+oleaut32!VarBstrCmp
+oleaut32!VarBstrFromBool
+oleaut32!VarBstrFromCy
+oleaut32!VarBstrFromDate
+oleaut32!VarBstrFromDec
+oleaut32!VarBstrFromDisp
+oleaut32!VarBstrFromI1
+oleaut32!VarBstrFromI2
+oleaut32!VarBstrFromI4
+oleaut32!VarBstrFromI8
+oleaut32!VarBstrFromR4
+oleaut32!VarBstrFromR8
+oleaut32!VarBstrFromUI1
+oleaut32!VarBstrFromUI2
+oleaut32!VarBstrFromUI4
+oleaut32!VarBstrFromUI8
+oleaut32!VarCat
+oleaut32!VarCmp
+oleaut32!VarCyAbs
+oleaut32!VarCyAdd
+oleaut32!VarCyCmp
+oleaut32!VarCyCmpR8
+oleaut32!VarCyFix
+oleaut32!VarCyFromBool
+oleaut32!VarCyFromDate
+oleaut32!VarCyFromDec
+oleaut32!VarCyFromDisp
+oleaut32!VarCyFromI1
+oleaut32!VarCyFromI2
+oleaut32!VarCyFromI4
+oleaut32!VarCyFromI8
+oleaut32!VarCyFromR4
+oleaut32!VarCyFromR8
+oleaut32!VarCyFromStr
+oleaut32!VarCyFromUI1
+oleaut32!VarCyFromUI2
+oleaut32!VarCyFromUI4
+oleaut32!VarCyFromUI8
+oleaut32!VarCyInt
+oleaut32!VarCyMul
+oleaut32!VarCyMulI4
+oleaut32!VarCyMulI8
+oleaut32!VarCyNeg
+oleaut32!VarCyRound
+oleaut32!VarCySub
+oleaut32!VarDateFromBool
+oleaut32!VarDateFromCy
+oleaut32!VarDateFromDec
+oleaut32!VarDateFromDisp
+oleaut32!VarDateFromI1
+oleaut32!VarDateFromI2
+oleaut32!VarDateFromI4
+oleaut32!VarDateFromI8
+oleaut32!VarDateFromR4
+oleaut32!VarDateFromR8
+oleaut32!VarDateFromStr
+oleaut32!VarDateFromUdate
+oleaut32!VarDateFromUdateEx
+oleaut32!VarDateFromUI1
+oleaut32!VarDateFromUI2
+oleaut32!VarDateFromUI4
+oleaut32!VarDateFromUI8
+oleaut32!VarDecAbs
+oleaut32!VarDecAdd
+oleaut32!VarDecCmp
+oleaut32!VarDecCmpR8
+oleaut32!VarDecDiv
+oleaut32!VarDecFix
+oleaut32!VarDecFromBool
+oleaut32!VarDecFromCy
+oleaut32!VarDecFromDate
+oleaut32!VarDecFromDisp
+oleaut32!VarDecFromI1
+oleaut32!VarDecFromI2
+oleaut32!VarDecFromI4
+oleaut32!VarDecFromI8
+oleaut32!VarDecFromR4
+oleaut32!VarDecFromR8
+oleaut32!VarDecFromStr
+oleaut32!VarDecFromUI1
+oleaut32!VarDecFromUI2
+oleaut32!VarDecFromUI4
+oleaut32!VarDecFromUI8
+oleaut32!VarDecInt
+oleaut32!VarDecMul
+oleaut32!VarDecNeg
+oleaut32!VarDecRound
+oleaut32!VarDecSub
+oleaut32!VarDiv
+oleaut32!VarEqv
+oleaut32!VarFix
+oleaut32!VarFormat
+oleaut32!VarFormatCurrency
+oleaut32!VarFormatDateTime
+oleaut32!VarFormatFromTokens
+oleaut32!VarFormatNumber
+oleaut32!VarFormatPercent
+oleaut32!VarI1FromBool
+oleaut32!VarI1FromCy
+oleaut32!VarI1FromDate
+oleaut32!VarI1FromDec
+oleaut32!VarI1FromDisp
+oleaut32!VarI1FromI2
+oleaut32!VarI1FromI4
+oleaut32!VarI1FromI8
+oleaut32!VarI1FromR4
+oleaut32!VarI1FromR8
+oleaut32!VarI1FromStr
+oleaut32!VarI1FromUI1
+oleaut32!VarI1FromUI2
+oleaut32!VarI1FromUI4
+oleaut32!VarI1FromUI8
+oleaut32!VarI2FromBool
+oleaut32!VarI2FromCy
+oleaut32!VarI2FromDate
+oleaut32!VarI2FromDec
+oleaut32!VarI2FromDisp
+oleaut32!VarI2FromI1
+oleaut32!VarI2FromI4
+oleaut32!VarI2FromI8
+oleaut32!VarI2FromR4
+oleaut32!VarI2FromR8
+oleaut32!VarI2FromStr
+oleaut32!VarI2FromUI1
+oleaut32!VarI2FromUI2
+oleaut32!VarI2FromUI4
+oleaut32!VarI2FromUI8
+oleaut32!VarI4FromBool
+oleaut32!VarI4FromCy
+oleaut32!VarI4FromDate
+oleaut32!VarI4FromDec
+oleaut32!VarI4FromDisp
+oleaut32!VarI4FromI1
+oleaut32!VarI4FromI2
+oleaut32!VarI4FromI8
+oleaut32!VarI4FromR4
+oleaut32!VarI4FromR8
+oleaut32!VarI4FromStr
+oleaut32!VarI4FromUI1
+oleaut32!VarI4FromUI2
+oleaut32!VarI4FromUI4
+oleaut32!VarI4FromUI8
+oleaut32!VarI8FromBool
+oleaut32!VarI8FromCy
+oleaut32!VarI8FromDate
+oleaut32!VarI8FromDec
+oleaut32!VarI8FromDisp
+oleaut32!VarI8FromI1
+oleaut32!VarI8FromI2
+oleaut32!VarI8FromR4
+oleaut32!VarI8FromR8
+oleaut32!VarI8FromStr
+oleaut32!VarI8FromUI1
+oleaut32!VarI8FromUI2
+oleaut32!VarI8FromUI4
+oleaut32!VarI8FromUI8
+oleaut32!VARIANT_UserFree
+oleaut32!VARIANT_UserMarshal
+oleaut32!VARIANT_UserSize
+oleaut32!VARIANT_UserUnmarshal
+oleaut32!VariantChangeType
+oleaut32!VariantChangeTypeEx
+oleaut32!VariantClear
+oleaut32!VariantCopy
+oleaut32!VariantCopyInd
+oleaut32!VariantInit
+oleaut32!VariantTimeToDosDateTime
+oleaut32!VariantTimeToSystemTime
+oleaut32!VarIdiv
+oleaut32!VarImp
+oleaut32!VarInt
+oleaut32!VarMod
+oleaut32!VarMonthName
+oleaut32!VarMul
+oleaut32!VarNeg
+oleaut32!VarNot
+oleaut32!VarNumFromParseNum
+oleaut32!VarOr
+oleaut32!VarParseNumFromStr
+oleaut32!VarPow
+oleaut32!VarR4CmpR8
+oleaut32!VarR4FromBool
+oleaut32!VarR4FromCy
+oleaut32!VarR4FromDate
+oleaut32!VarR4FromDec
+oleaut32!VarR4FromDisp
+oleaut32!VarR4FromI1
+oleaut32!VarR4FromI2
+oleaut32!VarR4FromI4
+oleaut32!VarR4FromI8
+oleaut32!VarR4FromR8
+oleaut32!VarR4FromStr
+oleaut32!VarR4FromUI1
+oleaut32!VarR4FromUI2
+oleaut32!VarR4FromUI4
+oleaut32!VarR4FromUI8
+oleaut32!VarR8FromBool
+oleaut32!VarR8FromCy
+oleaut32!VarR8FromDate
+oleaut32!VarR8FromDec
+oleaut32!VarR8FromDisp
+oleaut32!VarR8FromI1
+oleaut32!VarR8FromI2
+oleaut32!VarR8FromI4
+oleaut32!VarR8FromI8
+oleaut32!VarR8FromR4
+oleaut32!VarR8FromStr
+oleaut32!VarR8FromUI1
+oleaut32!VarR8FromUI2
+oleaut32!VarR8FromUI4
+oleaut32!VarR8FromUI8
+oleaut32!VarR8Pow
+oleaut32!VarR8Round
+oleaut32!VarRound
+oleaut32!VarSub
+oleaut32!VarTokenizeFormatString
+oleaut32!VarUdateFromDate
+oleaut32!VarUI1FromBool
+oleaut32!VarUI1FromCy
+oleaut32!VarUI1FromDate
+oleaut32!VarUI1FromDec
+oleaut32!VarUI1FromDisp
+oleaut32!VarUI1FromI1
+oleaut32!VarUI1FromI2
+oleaut32!VarUI1FromI4
+oleaut32!VarUI1FromI8
+oleaut32!VarUI1FromR4
+oleaut32!VarUI1FromR8
+oleaut32!VarUI1FromStr
+oleaut32!VarUI1FromUI2
+oleaut32!VarUI1FromUI4
+oleaut32!VarUI1FromUI8
+oleaut32!VarUI2FromBool
+oleaut32!VarUI2FromCy
+oleaut32!VarUI2FromDate
+oleaut32!VarUI2FromDec
+oleaut32!VarUI2FromDisp
+oleaut32!VarUI2FromI1
+oleaut32!VarUI2FromI2
+oleaut32!VarUI2FromI4
+oleaut32!VarUI2FromI8
+oleaut32!VarUI2FromR4
+oleaut32!VarUI2FromR8
+oleaut32!VarUI2FromStr
+oleaut32!VarUI2FromUI1
+oleaut32!VarUI2FromUI4
+oleaut32!VarUI2FromUI8
+oleaut32!VarUI4FromBool
+oleaut32!VarUI4FromCy
+oleaut32!VarUI4FromDate
+oleaut32!VarUI4FromDec
+oleaut32!VarUI4FromDisp
+oleaut32!VarUI4FromI1
+oleaut32!VarUI4FromI2
+oleaut32!VarUI4FromI4
+oleaut32!VarUI4FromI8
+oleaut32!VarUI4FromR4
+oleaut32!VarUI4FromR8
+oleaut32!VarUI4FromStr
+oleaut32!VarUI4FromUI1
+oleaut32!VarUI4FromUI2
+oleaut32!VarUI4FromUI8
+oleaut32!VarUI8FromBool
+oleaut32!VarUI8FromCy
+oleaut32!VarUI8FromDate
+oleaut32!VarUI8FromDec
+oleaut32!VarUI8FromDisp
+oleaut32!VarUI8FromI1
+oleaut32!VarUI8FromI2
+oleaut32!VarUI8FromI8
+oleaut32!VarUI8FromR4
+oleaut32!VarUI8FromR8
+oleaut32!VarUI8FromStr
+oleaut32!VarUI8FromUI1
+oleaut32!VarUI8FromUI2
+oleaut32!VarUI8FromUI4
+oleaut32!VarWeekdayName
+oleaut32!VarXor
+oleaut32!VectorFromBstr
+secur32!AcceptSecurityContext
+secur32!AcquireCredentialsHandleA
+secur32!AcquireCredentialsHandleW
+secur32!AddCredentialsA
+secur32!AddCredentialsW
+secur32!AddSecurityPackageA
+secur32!AddSecurityPackageW
+secur32!ApplyControlToken
+secur32!ChangeAccountPasswordA
+secur32!ChangeAccountPasswordW
+secur32!CompleteAuthToken
+secur32!DecryptMessage
+secur32!DeleteSecurityContext
+secur32!DeleteSecurityPackageA
+secur32!DeleteSecurityPackageW
+secur32!EncryptMessage
+secur32!EnumerateSecurityPackagesA
+secur32!EnumerateSecurityPackagesW
+secur32!ExportSecurityContext
+secur32!FreeContextBuffer
+secur32!FreeCredentialsHandle
+secur32!GetUserNameExA
+secur32!GetUserNameExW
+secur32!ImpersonateSecurityContext
+secur32!ImportSecurityContextA
+secur32!ImportSecurityContextW
+secur32!InitializeSecurityContextA
+secur32!InitializeSecurityContextW
+secur32!InitSecurityInterfaceA
+secur32!InitSecurityInterfaceW
+secur32!LsaCallAuthenticationPackage
+secur32!LsaConnectUntrusted
+secur32!LsaDeregisterLogonProcess
+secur32!LsaEnumerateLogonSessions
+secur32!LsaFreeReturnBuffer
+secur32!LsaGetLogonSessionData
+secur32!LsaLogonUser
+secur32!LsaLookupAuthenticationPackage
+secur32!LsaRegisterLogonProcess
+secur32!LsaRegisterPolicyChangeNotification
+secur32!LsaUnregisterPolicyChangeNotification
+secur32!MakeSignature
+secur32!QueryContextAttributesA
+secur32!QueryContextAttributesW
+secur32!QueryCredentialsAttributesA
+secur32!QueryCredentialsAttributesW
+secur32!QuerySecurityContextToken
+secur32!QuerySecurityPackageInfoA
+secur32!QuerySecurityPackageInfoW
+secur32!RevertSecurityContext
+secur32!SaslAcceptSecurityContext
+secur32!SaslEnumerateProfilesA
+secur32!SaslEnumerateProfilesW
+secur32!SaslGetContextOption
+secur32!SaslGetProfilePackageA
+secur32!SaslGetProfilePackageW
+secur32!SaslIdentifyPackageA
+secur32!SaslIdentifyPackageW
+secur32!SaslInitializeSecurityContextA
+secur32!SaslInitializeSecurityContextW
+secur32!SaslSetContextOption
+secur32!SealMessage
+secur32!SetContextAttributesA
+secur32!SetContextAttributesW
+secur32!SetCredentialsAttributesA
+secur32!SetCredentialsAttributesW
+secur32!SspiCompareAuthIdentities
+secur32!SspiCopyAuthIdentity
+secur32!SspiDecryptAuthIdentity
+secur32!SspiEncodeAuthIdentityAsStrings
+secur32!SspiEncodeStringsAsAuthIdentity
+secur32!SspiEncryptAuthIdentity
+secur32!SspiExcludePackage
+secur32!SspiFreeAuthIdentity
+secur32!SspiGetTargetHostName
+secur32!SspiIsAuthIdentityEncrypted
+secur32!SspiLocalFree
+secur32!SspiMarshalAuthIdentity
+secur32!SspiPrepareForCredRead
+secur32!SspiPrepareForCredWrite
+secur32!SspiUnmarshalAuthIdentity
+secur32!SspiValidateAuthIdentity
+secur32!SspiZeroAuthIdentity
+secur32!UnsealMessage
+secur32!VerifySignature
+user32!CharLowerBuffW
+user32!CharLowerW
+user32!CharNextW
+user32!CharPrevW
+user32!CharUpperBuffW
+user32!CharUpperW
+user32!IsCharAlphaNumericW
+user32!IsCharAlphaW
+user32!IsCharLowerW
+user32!IsCharUpperW
+user32!LoadStringA
+user32!LoadStringW
+version!GetFileVersionInfoExW
+version!GetFileVersionInfoSizeExW
+version!GetFileVersionInfoSizeW
+version!GetFileVersionInfoW
+version!VerFindFileW
+version!VerQueryValueW
+ws2_32!accept
+ws2_32!bind
+ws2_32!closesocket
+ws2_32!connect
+ws2_32!freeaddrinfo
+ws2_32!FreeAddrInfoEx
+ws2_32!FreeAddrInfoExW
+ws2_32!FreeAddrInfoW
+ws2_32!getaddrinfo
+ws2_32!GetAddrInfoExA
+ws2_32!GetAddrInfoExW
+ws2_32!GetAddrInfoW
+ws2_32!gethostbyaddr
+ws2_32!gethostbyname
+ws2_32!gethostname
+ws2_32!getnameinfo
+ws2_32!GetNameInfoW
+ws2_32!getpeername
+ws2_32!getprotobyname
+ws2_32!getprotobynumber
+ws2_32!getservbyname
+ws2_32!getservbyport
+ws2_32!getsockname
+ws2_32!getsockopt
+ws2_32!htonl
+ws2_32!htons
+ws2_32!inet_addr
+ws2_32!inet_ntoa
+ws2_32!inet_ntop
+ws2_32!inet_pton
+ws2_32!InetNtopW
+ws2_32!InetPtonW
+ws2_32!ioctlsocket
+ws2_32!listen
+ws2_32!ntohl
+ws2_32!ntohs
+ws2_32!recv
+ws2_32!recvfrom
+ws2_32!select
+ws2_32!send
+ws2_32!sendto
+ws2_32!SetAddrInfoExA
+ws2_32!SetAddrInfoExW
+ws2_32!setsockopt
+ws2_32!shutdown
+ws2_32!socket
+ws2_32!WPUCompleteOverlappedRequest
+ws2_32!WSAAccept
+ws2_32!WSAAddressToStringA
+ws2_32!WSAAddressToStringW
+ws2_32!WSAAdvertiseProvider
+ws2_32!WSAAsyncGetHostByAddr
+ws2_32!WSAAsyncGetHostByName
+ws2_32!WSAAsyncGetProtoByName
+ws2_32!WSAAsyncGetProtoByNumber
+ws2_32!WSAAsyncGetServByName
+ws2_32!WSAAsyncGetServByPort
+ws2_32!WSAAsyncSelect
+ws2_32!WSACancelAsyncRequest
+ws2_32!WSACancelBlockingCall
+ws2_32!WSACleanup
+ws2_32!WSACloseEvent
+ws2_32!WSAConnect
+ws2_32!WSAConnectByList
+ws2_32!WSAConnectByNameA
+ws2_32!WSAConnectByNameW
+ws2_32!WSACreateEvent
+ws2_32!WSADuplicateSocketA
+ws2_32!WSADuplicateSocketW
+ws2_32!WSAEnumNameSpaceProvidersA
+ws2_32!WSAEnumNameSpaceProvidersExA
+ws2_32!WSAEnumNameSpaceProvidersExW
+ws2_32!WSAEnumNameSpaceProvidersW
+ws2_32!WSAEnumNetworkEvents
+ws2_32!WSAEnumProtocolsA
+ws2_32!WSAEnumProtocolsW
+ws2_32!WSAEventSelect
+ws2_32!WSAGetLastError
+ws2_32!WSAGetOverlappedResult
+ws2_32!WSAGetQOSByName
+ws2_32!WSAGetServiceClassInfoA
+ws2_32!WSAGetServiceClassInfoW
+ws2_32!WSAGetServiceClassNameByClassIdA
+ws2_32!WSAGetServiceClassNameByClassIdW
+ws2_32!WSAHtonl
+ws2_32!WSAHtons
+ws2_32!WSAInstallServiceClassA
+ws2_32!WSAInstallServiceClassW
+ws2_32!WSAIoctl
+ws2_32!WSAIsBlocking
+ws2_32!WSAJoinLeaf
+ws2_32!WSALookupServiceBeginA
+ws2_32!WSALookupServiceBeginW
+ws2_32!WSALookupServiceEnd
+ws2_32!WSALookupServiceNextA
+ws2_32!WSALookupServiceNextW
+ws2_32!WSANSPIoctl
+ws2_32!WSANtohl
+ws2_32!WSANtohs
+ws2_32!WSAPoll
+ws2_32!WSAProviderCompleteAsyncCall
+ws2_32!WSAProviderConfigChange
+ws2_32!WSARecv
+ws2_32!WSARecvDisconnect
+ws2_32!WSARecvFrom
+ws2_32!WSARemoveServiceClass
+ws2_32!WSAResetEvent
+ws2_32!WSASend
+ws2_32!WSASendDisconnect
+ws2_32!WSASendMsg
+ws2_32!WSASendTo
+ws2_32!WSASetBlockingHook
+ws2_32!WSASetEvent
+ws2_32!WSASetLastError
+ws2_32!WSASetServiceA
+ws2_32!WSASetServiceW
+ws2_32!WSASocketA
+ws2_32!WSASocketW
+ws2_32!WSAStartup
+ws2_32!WSAStringToAddressA
+ws2_32!WSAStringToAddressW
+ws2_32!WSAUnadvertiseProvider
+ws2_32!WSAUnhookBlockingHook
+ws2_32!WSAWaitForMultipleEvents
+ws2_32!WSCDeinstallProvider
+ws2_32!WSCEnableNSProvider
+ws2_32!WSCEnumProtocols
+ws2_32!WSCGetApplicationCategory
+ws2_32!WSCGetProviderInfo
+ws2_32!WSCGetProviderPath
+ws2_32!WSCInstallNameSpace
+ws2_32!WSCInstallNameSpaceEx
+ws2_32!WSCInstallProvider
+ws2_32!WSCSetApplicationCategory
+ws2_32!WSCSetProviderInfo
+ws2_32!WSCUnInstallNameSpace
+ws2_32!WSCUpdateProvider
+ws2_32!WSCWriteNameSpaceOrder
+ws2_32!WSCWriteProviderOrder
diff --git a/src/coreclr/nativeaot/BuildIntegration/findvcvarsall.bat b/src/coreclr/nativeaot/BuildIntegration/findvcvarsall.bat
new file mode 100644
index 00000000000000..efee6316785f66
--- /dev/null
+++ b/src/coreclr/nativeaot/BuildIntegration/findvcvarsall.bat
@@ -0,0 +1,55 @@
+@ECHO OFF
+SETLOCAL
+
+IF "%~1"=="" (
+ ECHO Usage: %~nx0 ^
+ GOTO :ERROR
+)
+
+SET vswherePath=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
+IF NOT EXIST "%vswherePath%" GOTO :ERROR
+
+SET toolsSuffix=x86.x64
+IF /I "%~1"=="arm64" SET toolsSuffix=ARM64
+
+FOR /F "tokens=*" %%i IN (
+ '"%vswherePath%" -latest -prerelease -products * ^
+ -requires Microsoft.VisualStudio.Component.VC.Tools.%toolsSuffix% ^
+ -version [16^,18^) ^
+ -property installationPath'
+) DO SET vsBase=%%i
+
+IF "%vsBase%"=="" GOTO :ERROR
+
+SET procArch=%PROCESSOR_ARCHITEW6432%
+IF "%procArch%"=="" SET procArch=%PROCESSOR_ARCHITECTURE%
+
+SET vcEnvironment=%~1
+IF /I "%~1"=="x64" (
+ SET vcEnvironment=x86_amd64
+ IF /I "%procArch%"=="AMD64" SET vcEnvironment=amd64
+)
+IF /I "%~1"=="arm64" (
+ SET vcEnvironment=x86_arm64
+ IF /I "%procArch%"=="AMD64" SET vcEnvironment=amd64_arm64
+)
+
+CALL "%vsBase%\vc\Auxiliary\Build\vcvarsall.bat" %vcEnvironment% > NUL
+
+FOR /F "delims=" %%W IN ('where link') DO (
+ FOR %%A IN ("%%W") DO ECHO %%~dpA#
+ GOTO :CAPTURE_LIB_PATHS
+)
+
+GOTO :ERROR
+
+:CAPTURE_LIB_PATHS
+IF "%LIB%"=="" GOTO :ERROR
+ECHO %LIB%
+
+ENDLOCAL
+
+EXIT /B 0
+
+:ERROR
+EXIT /B 1
diff --git a/src/coreclr/nativeaot/CMakeLists.txt b/src/coreclr/nativeaot/CMakeLists.txt
new file mode 100644
index 00000000000000..05b92b3534fbbb
--- /dev/null
+++ b/src/coreclr/nativeaot/CMakeLists.txt
@@ -0,0 +1,50 @@
+if(WIN32)
+ add_definitions(-DUNICODE=1)
+endif (WIN32)
+
+if(MSVC)
+ add_compile_options($<$:/EHa->) # Native AOT runtime does not use C++ exception handling
+ add_compile_options($<$:/EHs->)
+
+ # CFG runtime checks in C++ code are unnecessary overhead unless Native AOT compiler produces CFG compliant code as well
+ # and CFG is enabled in the linker
+ if(CMAKE_CXX_FLAGS MATCHES "/guard:cf")
+ string(REPLACE "/guard:cf" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ endif()
+ if(CMAKE_C_FLAGS MATCHES "/guard:cf")
+ string(REPLACE "/guard:cf" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+ endif()
+
+ # The code generated by the Native AOT compiler doesn't work with Link Time Code Generation
+ add_compile_options($<$:/GL->)
+
+ # Sets the options that create the fastest code in the majority of cases
+ add_compile_options($<$,$>:/O2>)
+endif (MSVC)
+
+if(CLR_CMAKE_HOST_UNIX)
+ add_compile_options(-fno-rtti) # Native AOT runtime doesn't use RTTI
+ add_compile_options(-fno-exceptions) # Native AOT runtime doesn't use C++ exception handling
+
+ if(CLR_CMAKE_TARGET_OSX)
+ add_definitions(-D_XOPEN_SOURCE)
+ endif(CLR_CMAKE_TARGET_OSX)
+
+ if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
+ # Allow 16 byte compare-exchange
+ add_compile_options(-mcx16)
+ endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
+endif (CLR_CMAKE_HOST_UNIX)
+
+if(CLR_CMAKE_HOST_ALPINE_LINUX)
+ # Fix up the main thread stack size for MUSL to more reasonable size.
+ # TODO: https://github.com/dotnet/runtimelab/issues/791
+ add_definitions(-DENSURE_PRIMARY_STACK_SIZE)
+endif()
+
+if(CLR_CMAKE_TARGET_ANDROID)
+ add_definitions(-DFEATURE_EMULATED_TLS)
+endif()
+
+add_subdirectory(Bootstrap)
+add_subdirectory(Runtime)
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs
new file mode 100644
index 00000000000000..6d2506c01d7e06
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+using Debug = Internal.Runtime.CompilerHelpers.StartupDebug;
+
+namespace Internal.Runtime.CompilerHelpers
+{
+ public static partial class StartupCodeHelpers
+ {
+ ///
+ /// Initial module array allocation used when adding modules dynamically.
+ ///
+ private const int InitialModuleCount = 8;
+
+ ///
+ /// Table of logical modules. Only the first s_moduleCount elements of the array are in use.
+ ///
+ private static TypeManagerHandle[] s_modules;
+
+ ///
+ /// Number of valid elements in the logical module table.
+ ///
+ private static int s_moduleCount;
+
+ ///
+ /// GC handle of an array with s_moduleCount elements, each representing and array of GC static bases of the types in the module.
+ ///
+ private static IntPtr s_moduleGCStaticsSpines;
+
+ [UnmanagedCallersOnly(EntryPoint = "InitializeModules", CallConvs = new Type[] { typeof(CallConvCdecl) })]
+ internal static unsafe void InitializeModules(IntPtr osModule, IntPtr* pModuleHeaders, int count, IntPtr* pClasslibFunctions, int nClasslibFunctions)
+ {
+ RuntimeImports.RhpRegisterOsModule(osModule);
+ TypeManagerHandle[] modules = CreateTypeManagers(osModule, pModuleHeaders, count, pClasslibFunctions, nClasslibFunctions);
+ object[] gcStaticBaseSpines = new object[count];
+
+ for (int i = 0; i < modules.Length; i++)
+ {
+ InitializeGlobalTablesForModule(modules[i], i, gcStaticBaseSpines);
+ }
+
+ s_moduleGCStaticsSpines = RuntimeImports.RhHandleAlloc(gcStaticBaseSpines, GCHandleType.Normal);
+
+ // We are now at a stage where we can use GC statics - publish the list of modules
+ // so that the eager constructors can access it.
+ if (s_modules != null)
+ {
+ for (int i = 0; i < modules.Length; i++)
+ {
+ AddModule(modules[i]);
+ }
+ }
+ else
+ {
+ s_modules = modules;
+ s_moduleCount = modules.Length;
+ }
+
+ // These two loops look funny but it's important to initialize the global tables before running
+ // the first class constructor to prevent them calling into another uninitialized module
+ for (int i = 0; i < modules.Length; i++)
+ {
+ RunInitializers(modules[i], ReadyToRunSectionType.EagerCctor);
+ }
+ }
+
+ ///
+ /// Return the number of registered logical modules; optionally copy them into an array.
+ ///
+ /// Array to copy logical modules to, null = only return logical module count
+ internal static int GetLoadedModules(TypeManagerHandle[] outputModules)
+ {
+ if (outputModules != null)
+ {
+ int copyLimit = (s_moduleCount < outputModules.Length ? s_moduleCount : outputModules.Length);
+ for (int copyIndex = 0; copyIndex < copyLimit; copyIndex++)
+ {
+ outputModules[copyIndex] = s_modules[copyIndex];
+ }
+ }
+ return s_moduleCount;
+ }
+
+ private static void AddModule(TypeManagerHandle newModuleHandle)
+ {
+ if (s_modules == null || s_moduleCount >= s_modules.Length)
+ {
+ // Reallocate logical module array
+ int newModuleLength = 2 * s_moduleCount;
+ if (newModuleLength < InitialModuleCount)
+ {
+ newModuleLength = InitialModuleCount;
+ }
+
+ TypeManagerHandle[] newModules = new TypeManagerHandle[newModuleLength];
+ for (int copyIndex = 0; copyIndex < s_moduleCount; copyIndex++)
+ {
+ newModules[copyIndex] = s_modules[copyIndex];
+ }
+ s_modules = newModules;
+ }
+
+ s_modules[s_moduleCount] = newModuleHandle;
+ s_moduleCount++;
+ }
+
+ private static unsafe TypeManagerHandle[] CreateTypeManagers(IntPtr osModule, IntPtr* pModuleHeaders, int count, IntPtr* pClasslibFunctions, int nClasslibFunctions)
+ {
+ // Count the number of modules so we can allocate an array to hold the TypeManager objects.
+ // At this stage of startup, complex collection classes will not work.
+ int moduleCount = 0;
+ for (int i = 0; i < count; i++)
+ {
+ // The null pointers are sentinel values and padding inserted as side-effect of
+ // the section merging. (The global static constructors section used by C++ has
+ // them too.)
+ if (pModuleHeaders[i] != IntPtr.Zero)
+ moduleCount++;
+ }
+
+ TypeManagerHandle[] modules = new TypeManagerHandle[moduleCount];
+ int moduleIndex = 0;
+ for (int i = 0; i < count; i++)
+ {
+ if (pModuleHeaders[i] != IntPtr.Zero)
+ {
+ modules[moduleIndex] = RuntimeImports.RhpCreateTypeManager(osModule, pModuleHeaders[i], pClasslibFunctions, nClasslibFunctions);
+ moduleIndex++;
+ }
+ }
+
+ return modules;
+ }
+
+ ///
+ /// Each managed module linked into the final binary may have its own global tables for strings,
+ /// statics, etc that need initializing. InitializeGlobalTables walks through the modules
+ /// and offers each a chance to initialize its global tables.
+ ///
+ private static unsafe void InitializeGlobalTablesForModule(TypeManagerHandle typeManager, int moduleIndex, object[] gcStaticBaseSpines)
+ {
+ // Configure the module indirection cell with the newly created TypeManager. This allows EETypes to find
+ // their interface dispatch map tables.
+ int length;
+ TypeManagerSlot* section = (TypeManagerSlot*)RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.TypeManagerIndirection, out length);
+ section->TypeManager = typeManager;
+ section->ModuleIndex = moduleIndex;
+
+ // Initialize statics if any are present
+ IntPtr staticsSection = RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.GCStaticRegion, out length);
+ if (staticsSection != IntPtr.Zero)
+ {
+ Debug.Assert(length % IntPtr.Size == 0);
+
+ object[] spine = InitializeStatics(staticsSection, length);
+
+ // Call write barrier directly. Assigning object reference does a type check.
+ Debug.Assert((uint)moduleIndex < (uint)gcStaticBaseSpines.Length);
+ ref object rawSpineIndexData = ref Unsafe.As(ref Unsafe.As(gcStaticBaseSpines).Data);
+ InternalCalls.RhpAssignRef(ref Unsafe.Add(ref rawSpineIndexData, moduleIndex), spine);
+ }
+
+ // Initialize frozen object segment for the module with GC present
+ IntPtr frozenObjectSection = RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.FrozenObjectRegion, out length);
+ if (frozenObjectSection != IntPtr.Zero)
+ {
+ Debug.Assert(length % IntPtr.Size == 0);
+ InitializeModuleFrozenObjectSegment(frozenObjectSection, length);
+ }
+ }
+
+ private static unsafe void InitializeModuleFrozenObjectSegment(IntPtr segmentStart, int length)
+ {
+ if (RuntimeImports.RhpRegisterFrozenSegment(segmentStart, (IntPtr)length) == IntPtr.Zero)
+ {
+ // This should only happen if we ran out of memory.
+ RuntimeExceptionHelpers.FailFast("Failed to register frozen object segment for the module.");
+ }
+ }
+
+ internal static void RunModuleInitializers()
+ {
+ for (int i = 0; i < s_moduleCount; i++)
+ {
+ RunInitializers(s_modules[i], ReadyToRunSectionType.ModuleInitializerList);
+ }
+ }
+
+ private static unsafe void RunInitializers(TypeManagerHandle typeManager, ReadyToRunSectionType section)
+ {
+ var initializers = (delegate**)RuntimeImports.RhGetModuleSection(typeManager, section, out int length);
+ Debug.Assert(length % IntPtr.Size == 0);
+ int count = length / IntPtr.Size;
+ for (int i = 0; i < count; i++)
+ {
+ initializers[i]();
+ }
+ }
+
+ private static unsafe object[] InitializeStatics(IntPtr gcStaticRegionStart, int length)
+ {
+ IntPtr gcStaticRegionEnd = (IntPtr)((byte*)gcStaticRegionStart + length);
+
+ object[] spine = new object[length / IntPtr.Size];
+
+ ref object rawSpineData = ref Unsafe.As(ref Unsafe.As(spine).Data);
+
+ int currentBase = 0;
+ for (IntPtr* block = (IntPtr*)gcStaticRegionStart; block < (IntPtr*)gcStaticRegionEnd; block++)
+ {
+ // Gc Static regions can be shared by modules linked together during compilation. To ensure each
+ // is initialized once, the static region pointer is stored with lowest bit set in the image.
+ // The first time we initialize the static region its pointer is replaced with an object reference
+ // whose lowest bit is no longer set.
+ IntPtr* pBlock = (IntPtr*)*block;
+ nint blockAddr = *pBlock;
+ if ((blockAddr & GCStaticRegionConstants.Uninitialized) == GCStaticRegionConstants.Uninitialized)
+ {
+ object? obj = null;
+ RuntimeImports.RhAllocateNewObject(
+ new IntPtr(blockAddr & ~GCStaticRegionConstants.Mask),
+ (uint)GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP,
+ Unsafe.AsPointer(ref obj));
+ if (obj == null)
+ {
+ RuntimeExceptionHelpers.FailFast("Failed allocating GC static bases");
+ }
+
+
+ if ((blockAddr & GCStaticRegionConstants.HasPreInitializedData) == GCStaticRegionConstants.HasPreInitializedData)
+ {
+ // The next pointer is preinitialized data blob that contains preinitialized static GC fields,
+ // which are pointer relocs to GC objects in frozen segment.
+ // It actually has all GC fields including non-preinitialized fields and we simply copy over the
+ // entire blob to this object, overwriting everything.
+ IntPtr pPreInitDataAddr = *(pBlock + 1);
+ RuntimeImports.RhBulkMoveWithWriteBarrier(ref obj.GetRawData(), ref *(byte *)pPreInitDataAddr, obj.GetRawDataSize());
+ }
+
+ // Call write barrier directly. Assigning object reference does a type check.
+ Debug.Assert(currentBase < spine.Length);
+ InternalCalls.RhpAssignRef(ref Unsafe.Add(ref rawSpineData, currentBase), obj);
+
+ // Update the base pointer to point to the pinned object
+ *pBlock = *(IntPtr*)Unsafe.AsPointer(ref obj);
+ }
+
+ currentBase++;
+ }
+
+ return spine;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct TypeManagerSlot
+ {
+ public TypeManagerHandle TypeManager;
+ public int ModuleIndex;
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupDebug.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupDebug.cs
new file mode 100644
index 00000000000000..b69af16e839717
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupDebug.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+
+namespace Internal.Runtime.CompilerHelpers
+{
+ ///
+ /// replacement for the startup path.
+ /// It's not safe to use the full-blown Debug class during startup because big chunks
+ /// of the managed execution environment are not initialized yet.
+ ///
+ internal static class StartupDebug
+ {
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition)
+ {
+ if (!condition)
+ unsafe { *(int*)0 = 0; }
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/LowLevelStringConverter.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/LowLevelStringConverter.cs
new file mode 100644
index 00000000000000..99487b5c8e36f0
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/LowLevelStringConverter.cs
@@ -0,0 +1,55 @@
+// 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.Text;
+
+namespace Internal.Runtime
+{
+ ///
+ /// Extension methods that provide low level ToString() equivalents for some of the core types.
+ /// Calling regular ToString() on these types goes through a lot of the CultureInfo machinery
+ /// which is not low level enough to be used everywhere.
+ ///
+ internal static class LowLevelStringConverter
+ {
+ private const string HexDigits = "0123456789ABCDEF";
+
+ // TODO: Rename to ToHexString()
+ public static string LowLevelToString(this int arg)
+ {
+ return ((uint)arg).LowLevelToString();
+ }
+
+ // TODO: Rename to ToHexString()
+ public static string LowLevelToString(this uint arg)
+ {
+ StringBuilder sb = new StringBuilder(8);
+ int shift = 4 * 8;
+ while (shift > 0)
+ {
+ shift -= 4;
+ int digit = (int)((arg >> shift) & 0xF);
+ sb.Append(HexDigits[digit]);
+ }
+
+ return sb.ToString();
+ }
+
+ public static string LowLevelToString(this IntPtr arg)
+ {
+ StringBuilder sb = new StringBuilder(IntPtr.Size * 4);
+ ulong num = (ulong)arg;
+
+ int shift = IntPtr.Size * 8;
+ while (shift > 0)
+ {
+ shift -= 4;
+ int digit = (int)((num >> shift) & 0xF);
+ sb.Append(HexDigits[digit]);
+ }
+
+ return sb.ToString();
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
new file mode 100644
index 00000000000000..007e940bec2795
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
@@ -0,0 +1,1662 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Internal.NativeFormat;
+using Internal.Runtime.CompilerServices;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.Runtime
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ObjHeader
+ {
+ // Contents of the object header
+ private IntPtr _objHeaderContents;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct EEInterfaceInfo
+ {
+ [StructLayout(LayoutKind.Explicit)]
+ private unsafe struct InterfaceTypeUnion
+ {
+ [FieldOffset(0)]
+ public MethodTable* _pInterfaceEEType;
+ [FieldOffset(0)]
+ public MethodTable** _ppInterfaceEETypeViaIAT;
+ }
+
+ private InterfaceTypeUnion _interfaceType;
+
+ internal MethodTable* InterfaceType
+ {
+ get
+ {
+ if ((unchecked((uint)_interfaceType._pInterfaceEEType) & IndirectionConstants.IndirectionCellPointer) != 0)
+ {
+#if TARGET_64BIT
+ MethodTable** ppInterfaceEETypeViaIAT = (MethodTable**)(((ulong)_interfaceType._ppInterfaceEETypeViaIAT) - IndirectionConstants.IndirectionCellPointer);
+#else
+ MethodTable** ppInterfaceEETypeViaIAT = (MethodTable**)(((uint)_interfaceType._ppInterfaceEETypeViaIAT) - IndirectionConstants.IndirectionCellPointer);
+#endif
+ return *ppInterfaceEETypeViaIAT;
+ }
+
+ return _interfaceType._pInterfaceEEType;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _interfaceType._pInterfaceEEType = value;
+ }
+#endif
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct DispatchMap
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct DispatchMapEntry
+ {
+ internal ushort _usInterfaceIndex;
+ internal ushort _usInterfaceMethodSlot;
+ internal ushort _usImplMethodSlot;
+ }
+
+ private ushort _standardEntryCount; // Implementations on the class
+ private ushort _defaultEntryCount; // Default implementations
+ private DispatchMapEntry _dispatchMap; // at least one entry if any interfaces defined
+
+ public uint NumStandardEntries
+ {
+ get
+ {
+ return _standardEntryCount;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _standardEntryCount = checked((ushort)value);
+ }
+#endif
+ }
+
+ public uint NumDefaultEntries
+ {
+ get
+ {
+ return _defaultEntryCount;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _defaultEntryCount = checked((ushort)value);
+ }
+#endif
+ }
+
+ public int Size
+ {
+ get
+ {
+ return sizeof(ushort) + sizeof(ushort) + sizeof(DispatchMapEntry) * ((int)_standardEntryCount + (int)_defaultEntryCount);
+ }
+ }
+
+ public DispatchMapEntry* this[int index]
+ {
+ get
+ {
+ return (DispatchMapEntry*)Unsafe.AsPointer(ref Unsafe.Add(ref _dispatchMap, index));
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe partial struct MethodTable
+ {
+#if TARGET_64BIT
+ private const int POINTER_SIZE = 8;
+ private const int PADDING = 1; // _numComponents is padded by one Int32 to make the first element pointer-aligned
+#else
+ private const int POINTER_SIZE = 4;
+ private const int PADDING = 0;
+#endif
+ internal const int SZARRAY_BASE_SIZE = POINTER_SIZE + POINTER_SIZE + (1 + PADDING) * 4;
+
+ [StructLayout(LayoutKind.Explicit)]
+ private unsafe struct RelatedTypeUnion
+ {
+ // Kinds.CanonicalEEType
+ [FieldOffset(0)]
+ public MethodTable* _pBaseType;
+ [FieldOffset(0)]
+ public MethodTable** _ppBaseTypeViaIAT;
+
+ // Kinds.ClonedEEType
+ [FieldOffset(0)]
+ public MethodTable* _pCanonicalType;
+ [FieldOffset(0)]
+ public MethodTable** _ppCanonicalTypeViaIAT;
+
+ // Kinds.ArrayEEType
+ [FieldOffset(0)]
+ public MethodTable* _pRelatedParameterType;
+ [FieldOffset(0)]
+ public MethodTable** _ppRelatedParameterTypeViaIAT;
+ }
+
+ private static unsafe class OptionalFieldsReader
+ {
+ internal static uint GetInlineField(byte* pFields, EETypeOptionalFieldTag eTag, uint uiDefaultValue)
+ {
+ if (pFields == null)
+ return uiDefaultValue;
+
+ bool isLastField = false;
+ while (!isLastField)
+ {
+ byte fieldHeader = NativePrimitiveDecoder.ReadUInt8(ref pFields);
+ isLastField = (fieldHeader & 0x80) != 0;
+ EETypeOptionalFieldTag eCurrentTag = (EETypeOptionalFieldTag)(fieldHeader & 0x7f);
+ uint uiCurrentValue = NativePrimitiveDecoder.DecodeUnsigned(ref pFields);
+
+ // If we found a tag match return the current value.
+ if (eCurrentTag == eTag)
+ return uiCurrentValue;
+ }
+
+ // Reached end of stream without getting a match. Field is not present so return default value.
+ return uiDefaultValue;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether the statically generated data structures use relative pointers.
+ ///
+ internal static bool SupportsRelativePointers
+ {
+ [Intrinsic]
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether writable data is supported.
+ ///
+ internal static bool SupportsWritableData
+ {
+ get
+ {
+ // For now just key this off of SupportsRelativePointer to avoid this on both CppCodegen and WASM.
+ return SupportsRelativePointers;
+ }
+ }
+
+ private ushort _usComponentSize;
+ private ushort _usFlags;
+ private uint _uBaseSize;
+ private RelatedTypeUnion _relatedType;
+ private ushort _usNumVtableSlots;
+ private ushort _usNumInterfaces;
+ private uint _uHashCode;
+
+ // vtable follows
+
+ // These masks and paddings have been chosen so that the ValueTypePadding field can always fit in a byte of data.
+ // if the alignment is 8 bytes or less. If the alignment is higher then there may be a need for more bits to hold
+ // the rest of the padding data.
+ // If paddings of greater than 7 bytes are necessary, then the high bits of the field represent that padding
+ private const uint ValueTypePaddingLowMask = 0x7;
+ private const uint ValueTypePaddingHighMask = 0xFFFFFF00;
+ private const uint ValueTypePaddingMax = 0x07FFFFFF;
+ private const int ValueTypePaddingHighShift = 8;
+ private const uint ValueTypePaddingAlignmentMask = 0xF8;
+ private const int ValueTypePaddingAlignmentShift = 3;
+
+ internal ushort ComponentSize
+ {
+ get
+ {
+ return _usComponentSize;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _usComponentSize = value;
+ }
+#endif
+ }
+
+ internal ushort GenericArgumentCount
+ {
+ get
+ {
+ Debug.Assert(IsGenericTypeDefinition);
+ return _usComponentSize;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsGenericTypeDefinition);
+ _usComponentSize = value;
+ }
+#endif
+ }
+
+ internal ushort Flags
+ {
+ get
+ {
+ return _usFlags;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _usFlags = value;
+ }
+#endif
+ }
+
+ internal uint BaseSize
+ {
+ get
+ {
+ return _uBaseSize;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _uBaseSize = value;
+ }
+#endif
+ }
+
+ internal ushort NumVtableSlots
+ {
+ get
+ {
+ return _usNumVtableSlots;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _usNumVtableSlots = value;
+ }
+#endif
+ }
+
+ internal ushort NumInterfaces
+ {
+ get
+ {
+ return _usNumInterfaces;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _usNumInterfaces = value;
+ }
+#endif
+ }
+
+ internal uint HashCode
+ {
+ get
+ {
+ return _uHashCode;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _uHashCode = value;
+ }
+#endif
+ }
+
+ private EETypeKind Kind
+ {
+ get
+ {
+ return (EETypeKind)(_usFlags & (ushort)EETypeFlags.EETypeKindMask);
+ }
+ }
+
+ internal bool HasOptionalFields
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.OptionalFieldsFlag) != 0);
+ }
+ }
+
+ // Mark or determine that a type is generic and one or more of it's type parameters is co- or
+ // contra-variant. This only applies to interface and delegate types.
+ internal bool HasGenericVariance
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.GenericVarianceFlag) != 0);
+ }
+ }
+
+ internal bool IsFinalizable
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.HasFinalizerFlag) != 0);
+ }
+ }
+
+ internal bool IsNullable
+ {
+ get
+ {
+ return ElementType == EETypeElementType.Nullable;
+ }
+ }
+
+ internal bool IsCloned
+ {
+ get
+ {
+ return Kind == EETypeKind.ClonedEEType;
+ }
+ }
+
+ internal bool IsCanonical
+ {
+ get
+ {
+ return Kind == EETypeKind.CanonicalEEType;
+ }
+ }
+
+ internal bool IsString
+ {
+ get
+ {
+ // String is currently the only non-array type with a non-zero component size.
+ return ComponentSize == StringComponentSize.Value && !IsArray && !IsGenericTypeDefinition;
+ }
+ }
+
+ internal bool IsArray
+ {
+ get
+ {
+ EETypeElementType elementType = ElementType;
+ return elementType == EETypeElementType.Array || elementType == EETypeElementType.SzArray;
+ }
+ }
+
+
+ internal int ArrayRank
+ {
+ get
+ {
+ Debug.Assert(this.IsArray);
+
+ int boundsSize = (int)this.ParameterizedTypeShape - SZARRAY_BASE_SIZE;
+ if (boundsSize > 0)
+ {
+ // Multidim array case: Base size includes space for two Int32s
+ // (upper and lower bound) per each dimension of the array.
+ return boundsSize / (2 * sizeof(int));
+ }
+ return 1;
+ }
+ }
+
+ internal bool IsSzArray
+ {
+ get
+ {
+ return ElementType == EETypeElementType.SzArray;
+ }
+ }
+
+ internal bool IsGeneric
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.IsGenericFlag) != 0);
+ }
+ }
+
+ internal bool IsGenericTypeDefinition
+ {
+ get
+ {
+ return Kind == EETypeKind.GenericTypeDefEEType;
+ }
+ }
+
+ internal MethodTable* GenericDefinition
+ {
+ get
+ {
+ Debug.Assert(IsGeneric);
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField>(EETypeField.ETF_GenericDefinition).Value;
+
+ return GetField>(EETypeField.ETF_GenericDefinition).Value;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsGeneric && IsDynamicType);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_GenericDefinition);
+ fixed (MethodTable* pThis = &this)
+ {
+ *((MethodTable**)((byte*)pThis + cbOffset)) = value;
+ }
+ }
+#endif
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private readonly struct GenericComposition
+ {
+ public readonly ushort Arity;
+
+ private readonly EETypeRef _genericArgument1;
+ public EETypeRef* GenericArguments
+ {
+ get
+ {
+ return (EETypeRef*)Unsafe.AsPointer(ref Unsafe.AsRef(in _genericArgument1));
+ }
+ }
+
+ public GenericVariance* GenericVariance
+ {
+ get
+ {
+ // Generic variance directly follows the last generic argument
+ return (GenericVariance*)(GenericArguments + Arity);
+ }
+ }
+ }
+
+#if TYPE_LOADER_IMPLEMENTATION
+ internal static int GetGenericCompositionSize(int numArguments, bool hasVariance)
+ {
+ return IntPtr.Size
+ + numArguments * IntPtr.Size
+ + (hasVariance ? numArguments * sizeof(GenericVariance) : 0);
+ }
+
+ internal void SetGenericComposition(IntPtr data)
+ {
+ Debug.Assert(IsGeneric && IsDynamicType);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_GenericComposition);
+ fixed (MethodTable* pThis = &this)
+ {
+ *((IntPtr*)((byte*)pThis + cbOffset)) = data;
+ }
+ }
+#endif
+
+ internal uint GenericArity
+ {
+ get
+ {
+ Debug.Assert(IsGeneric);
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField>(EETypeField.ETF_GenericComposition).Value->Arity;
+
+ return GetField>(EETypeField.ETF_GenericComposition).Value->Arity;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType);
+ // GenericComposition is a readonly struct, so we just blit the bytes over. Asserts guard changes to the layout.
+ *((ushort*)GetField>(EETypeField.ETF_GenericComposition).Value) = checked((ushort)value);
+ Debug.Assert(GenericArity == (ushort)value);
+ }
+#endif
+ }
+
+ internal EETypeRef* GenericArguments
+ {
+ get
+ {
+ Debug.Assert(IsGeneric);
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField>(EETypeField.ETF_GenericComposition).Value->GenericArguments;
+
+ return GetField>(EETypeField.ETF_GenericComposition).Value->GenericArguments;
+ }
+ }
+
+ internal GenericVariance* GenericVariance
+ {
+ get
+ {
+ Debug.Assert(IsGeneric);
+
+ if (!HasGenericVariance)
+ return null;
+
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField>(EETypeField.ETF_GenericComposition).Value->GenericVariance;
+
+ return GetField>(EETypeField.ETF_GenericComposition).Value->GenericVariance;
+ }
+ }
+
+ internal bool IsPointerType
+ {
+ get
+ {
+ return ElementType == EETypeElementType.Pointer;
+ }
+ }
+
+ internal bool IsByRefType
+ {
+ get
+ {
+ return ElementType == EETypeElementType.ByRef;
+ }
+ }
+
+ internal bool IsInterface
+ {
+ get
+ {
+ return ElementType == EETypeElementType.Interface;
+ }
+ }
+
+ internal bool IsAbstract
+ {
+ get
+ {
+ return IsInterface || (RareFlags & EETypeRareFlags.IsAbstractClassFlag) != 0;
+ }
+ }
+
+ internal bool IsByRefLike
+ {
+ get
+ {
+ return (RareFlags & EETypeRareFlags.IsByRefLikeFlag) != 0;
+ }
+ }
+
+ internal bool IsDynamicType
+ {
+ get
+ {
+ return (_usFlags & (ushort)EETypeFlags.IsDynamicTypeFlag) != 0;
+ }
+ }
+
+ internal bool HasDynamicallyAllocatedDispatchMap
+ {
+ get
+ {
+ return (RareFlags & EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag) != 0;
+ }
+ }
+
+ internal bool IsParameterizedType
+ {
+ get
+ {
+ return Kind == EETypeKind.ParameterizedEEType;
+ }
+ }
+
+ // The parameterized type shape defines the particular form of parameterized type that
+ // is being represented.
+ // Currently, the meaning is a shape of 0 indicates that this is a Pointer,
+ // shape of 1 indicates a ByRef, and >=SZARRAY_BASE_SIZE indicates that this is an array.
+ // Two types are not equivalent if their shapes do not exactly match.
+ internal uint ParameterizedTypeShape
+ {
+ get
+ {
+ return _uBaseSize;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _uBaseSize = value;
+ }
+#endif
+ }
+
+ internal bool IsRelatedTypeViaIAT
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.RelatedTypeViaIATFlag) != 0);
+ }
+ }
+
+ internal bool RequiresAlign8
+ {
+ get
+ {
+ return (RareFlags & EETypeRareFlags.RequiresAlign8Flag) != 0;
+ }
+ }
+
+ internal bool IsIDynamicInterfaceCastable
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.IDynamicInterfaceCastableFlag) != 0);
+ }
+ }
+
+ internal bool IsValueType
+ {
+ get
+ {
+ return ElementType < EETypeElementType.Class;
+ }
+ }
+
+ // Warning! UNLIKE the similarly named Reflection api, this method also returns "true" for Enums.
+ internal bool IsPrimitive
+ {
+ get
+ {
+ return ElementType < EETypeElementType.ValueType;
+ }
+ }
+
+ internal bool HasGCPointers
+ {
+ get
+ {
+ return ((_usFlags & (ushort)EETypeFlags.HasPointersFlag) != 0);
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ if (value)
+ {
+ _usFlags |= (ushort)EETypeFlags.HasPointersFlag;
+ }
+ else
+ {
+ _usFlags &= (ushort)~EETypeFlags.HasPointersFlag;
+ }
+ }
+#endif
+ }
+
+ internal bool IsHFA
+ {
+ get
+ {
+ return (RareFlags & EETypeRareFlags.IsHFAFlag) != 0;
+ }
+ }
+
+ internal uint ValueTypeFieldPadding
+ {
+ get
+ {
+ byte* optionalFields = OptionalFieldsPtr;
+
+ // If there are no optional fields then the padding must have been the default, 0.
+ if (optionalFields == null)
+ return 0;
+
+ // Get the value from the optional fields. The default is zero if that particular field was not included.
+ // The low bits of this field is the ValueType field padding, the rest of the byte is the alignment if present
+ uint ValueTypeFieldPaddingData = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.ValueTypeFieldPadding, 0);
+ uint padding = ValueTypeFieldPaddingData & ValueTypePaddingLowMask;
+ // If there is additional padding, the other bits have that data
+ padding |= (ValueTypeFieldPaddingData & ValueTypePaddingHighMask) >> (ValueTypePaddingHighShift - ValueTypePaddingAlignmentShift);
+ return padding;
+ }
+ }
+
+ internal uint ValueTypeSize
+ {
+ get
+ {
+ Debug.Assert(IsValueType);
+ // get_BaseSize returns the GC size including space for the sync block index field, the MethodTable* and
+ // padding for GC heap alignment. Must subtract all of these to get the size used for locals, array
+ // elements or fields of another type.
+ return BaseSize - ((uint)sizeof(ObjHeader) + (uint)sizeof(MethodTable*) + ValueTypeFieldPadding);
+ }
+ }
+
+ internal uint FieldByteCountNonGCAligned
+ {
+ get
+ {
+ // This api is designed to return correct results for EETypes which can be derived from
+ // And results indistinguishable from correct for DefTypes which cannot be derived from (sealed classes)
+ // (For sealed classes, this should always return BaseSize-((uint)sizeof(ObjHeader));
+ Debug.Assert(!IsInterface && !IsParameterizedType);
+
+ // get_BaseSize returns the GC size including space for the sync block index field, the MethodTable* and
+ // padding for GC heap alignment. Must subtract all of these to get the size used for the fields of
+ // the type (where the fields of the type includes the MethodTable*)
+ return BaseSize - ((uint)sizeof(ObjHeader) + ValueTypeFieldPadding);
+ }
+ }
+
+ internal EEInterfaceInfo* InterfaceMap
+ {
+ get
+ {
+ fixed (MethodTable* start = &this)
+ {
+ // interface info table starts after the vtable and has _usNumInterfaces entries
+ return (EEInterfaceInfo*)((byte*)start + sizeof(MethodTable) + sizeof(void*) * _usNumVtableSlots);
+ }
+ }
+ }
+
+ internal bool HasDispatchMap
+ {
+ get
+ {
+ if (NumInterfaces == 0)
+ return false;
+ byte* optionalFields = OptionalFieldsPtr;
+ if (optionalFields == null)
+ return false;
+ uint idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, 0xffffffff);
+ if (idxDispatchMap == 0xffffffff)
+ {
+ if (HasDynamicallyAllocatedDispatchMap)
+ return true;
+ else if (IsDynamicType)
+ return DynamicTemplateType->HasDispatchMap;
+ return false;
+ }
+ return true;
+ }
+ }
+
+ internal DispatchMap* DispatchMap
+ {
+ get
+ {
+ if (NumInterfaces == 0)
+ return null;
+ byte* optionalFields = OptionalFieldsPtr;
+ if (optionalFields == null)
+ return null;
+ uint idxDispatchMap = OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.DispatchMap, 0xffffffff);
+ if (idxDispatchMap == 0xffffffff && IsDynamicType)
+ {
+ if (HasDynamicallyAllocatedDispatchMap)
+ {
+ fixed (MethodTable* pThis = &this)
+ return *(DispatchMap**)((byte*)pThis + GetFieldOffset(EETypeField.ETF_DynamicDispatchMap));
+ }
+ else
+ return DynamicTemplateType->DispatchMap;
+ }
+
+ return ((DispatchMap**)TypeManager.DispatchMap)[idxDispatchMap];
+ }
+ }
+
+ // Get the address of the finalizer method for finalizable types.
+ internal IntPtr FinalizerCode
+ {
+ get
+ {
+ Debug.Assert(IsFinalizable);
+
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField(EETypeField.ETF_Finalizer).Value;
+
+ return GetField(EETypeField.ETF_Finalizer).Value;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType && IsFinalizable);
+
+ fixed (MethodTable* pThis = &this)
+ *(IntPtr*)((byte*)pThis + GetFieldOffset(EETypeField.ETF_Finalizer)) = value;
+ }
+#endif
+ }
+
+ internal MethodTable* BaseType
+ {
+ get
+ {
+ if (IsCloned)
+ {
+ return CanonicalEEType->BaseType;
+ }
+
+ if (IsParameterizedType)
+ {
+ if (IsArray)
+ return GetArrayEEType();
+ else
+ return null;
+ }
+
+ Debug.Assert(IsCanonical);
+
+ if (IsRelatedTypeViaIAT)
+ return *_relatedType._ppBaseTypeViaIAT;
+ else
+ return _relatedType._pBaseType;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType);
+ Debug.Assert(!IsParameterizedType);
+ Debug.Assert(!IsCloned);
+ Debug.Assert(IsCanonical);
+ _usFlags &= (ushort)~EETypeFlags.RelatedTypeViaIATFlag;
+ _relatedType._pBaseType = value;
+ }
+#endif
+ }
+
+ internal MethodTable* NonArrayBaseType
+ {
+ get
+ {
+ Debug.Assert(!IsArray, "array type not supported in BaseType");
+
+ if (IsCloned)
+ {
+ // Assuming that since this is not an Array, the CanonicalEEType is also not an array
+ return CanonicalEEType->NonArrayBaseType;
+ }
+
+ Debug.Assert(IsCanonical, "we expect canonical types here");
+
+ if (IsRelatedTypeViaIAT)
+ {
+ return *_relatedType._ppBaseTypeViaIAT;
+ }
+
+ return _relatedType._pBaseType;
+ }
+ }
+
+ internal MethodTable* NonClonedNonArrayBaseType
+ {
+ get
+ {
+ Debug.Assert(!IsArray, "array type not supported in NonArrayBaseType");
+ Debug.Assert(!IsCloned, "cloned type not supported in NonClonedNonArrayBaseType");
+ Debug.Assert(IsCanonical || IsGenericTypeDefinition, "we expect canonical types here");
+
+ if (IsRelatedTypeViaIAT)
+ {
+ return *_relatedType._ppBaseTypeViaIAT;
+ }
+
+ return _relatedType._pBaseType;
+ }
+ }
+
+ internal MethodTable* RawBaseType
+ {
+ get
+ {
+ Debug.Assert(!IsParameterizedType, "array type not supported in NonArrayBaseType");
+ Debug.Assert(!IsCloned, "cloned type not supported in NonClonedNonArrayBaseType");
+ Debug.Assert(IsCanonical, "we expect canonical types here");
+ Debug.Assert(!IsRelatedTypeViaIAT, "Non IAT");
+
+ return _relatedType._pBaseType;
+ }
+ }
+
+ internal MethodTable* CanonicalEEType
+ {
+ get
+ {
+ // cloned EETypes must always refer to types in other modules
+ Debug.Assert(IsCloned);
+ if (IsRelatedTypeViaIAT)
+ return *_relatedType._ppCanonicalTypeViaIAT;
+ else
+ return _relatedType._pCanonicalType;
+ }
+ }
+
+ internal MethodTable* NullableType
+ {
+ get
+ {
+ Debug.Assert(IsNullable);
+ Debug.Assert(GenericArity == 1);
+ return GenericArguments[0].Value;
+ }
+ }
+
+ ///
+ /// Gets the offset of the value embedded in a Nullable<T>.
+ ///
+ internal byte NullableValueOffset
+ {
+ get
+ {
+ Debug.Assert(IsNullable);
+
+ // Grab optional fields. If there aren't any then the offset was the default of 1 (immediately after the
+ // Nullable's boolean flag).
+ byte* optionalFields = OptionalFieldsPtr;
+ if (optionalFields == null)
+ return 1;
+
+ // The offset is never zero (Nullable has a boolean there indicating whether the value is valid). So the
+ // offset is encoded - 1 to save space. The zero below is the default value if the field wasn't encoded at
+ // all.
+ return (byte)(OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.NullableValueOffset, 0) + 1);
+ }
+ }
+
+ internal MethodTable* RelatedParameterType
+ {
+ get
+ {
+ Debug.Assert(IsParameterizedType);
+
+ if (IsRelatedTypeViaIAT)
+ return *_relatedType._ppRelatedParameterTypeViaIAT;
+ else
+ return _relatedType._pRelatedParameterType;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType && IsParameterizedType);
+ _usFlags &= ((ushort)~EETypeFlags.RelatedTypeViaIATFlag);
+ _relatedType._pRelatedParameterType = value;
+ }
+#endif
+ }
+
+ internal unsafe IntPtr* GetVTableStartAddress()
+ {
+ byte* pResult;
+
+ // EETypes are always in unmanaged memory, so 'leaking' the 'fixed pointer' is safe.
+ fixed (MethodTable* pThis = &this)
+ pResult = (byte*)pThis;
+
+ pResult += sizeof(MethodTable);
+ return (IntPtr*)pResult;
+ }
+
+ private static IntPtr FollowRelativePointer(int* pDist)
+ {
+ int dist = *pDist;
+ IntPtr result = (IntPtr)((byte*)pDist + dist);
+ return result;
+ }
+
+ internal IntPtr GetSealedVirtualSlot(ushort slotNumber)
+ {
+ Debug.Assert((RareFlags & EETypeRareFlags.HasSealedVTableEntriesFlag) != 0);
+
+ fixed (MethodTable* pThis = &this)
+ {
+ if (IsDynamicType || !SupportsRelativePointers)
+ {
+ uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
+ IntPtr* pSealedVirtualsSlotTable = *(IntPtr**)((byte*)pThis + cbSealedVirtualSlotsTypeOffset);
+ return pSealedVirtualsSlotTable[slotNumber];
+ }
+ else
+ {
+ uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
+ int* pSealedVirtualsSlotTable = (int*)FollowRelativePointer((int*)((byte*)pThis + cbSealedVirtualSlotsTypeOffset));
+ IntPtr result = FollowRelativePointer(&pSealedVirtualsSlotTable[slotNumber]);
+ return result;
+ }
+ }
+ }
+
+#if TYPE_LOADER_IMPLEMENTATION
+ internal void SetSealedVirtualSlot(IntPtr value, ushort slotNumber)
+ {
+ Debug.Assert(IsDynamicType);
+
+ fixed (MethodTable* pThis = &this)
+ {
+ uint cbSealedVirtualSlotsTypeOffset = GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
+ IntPtr* pSealedVirtualsSlotTable = *(IntPtr**)((byte*)pThis + cbSealedVirtualSlotsTypeOffset);
+ pSealedVirtualsSlotTable[slotNumber] = value;
+ }
+ }
+#endif
+
+ internal byte* OptionalFieldsPtr
+ {
+ get
+ {
+ if (!HasOptionalFields)
+ return null;
+
+ if (IsDynamicType || !SupportsRelativePointers)
+ return GetField>(EETypeField.ETF_OptionalFieldsPtr).Value;
+
+ return GetField>(EETypeField.ETF_OptionalFieldsPtr).Value;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType);
+
+ _usFlags |= (ushort)EETypeFlags.OptionalFieldsFlag;
+
+ uint cbOptionalFieldsOffset = GetFieldOffset(EETypeField.ETF_OptionalFieldsPtr);
+ fixed (MethodTable* pThis = &this)
+ {
+ *(byte**)((byte*)pThis + cbOptionalFieldsOffset) = value;
+ }
+ }
+#endif
+ }
+
+ internal MethodTable* DynamicTemplateType
+ {
+ get
+ {
+ Debug.Assert(IsDynamicType);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicTemplateType);
+ fixed (MethodTable* pThis = &this)
+ {
+ return *(MethodTable**)((byte*)pThis + cbOffset);
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicTemplateType);
+ fixed (MethodTable* pThis = &this)
+ {
+ *(MethodTable**)((byte*)pThis + cbOffset) = value;
+ }
+ }
+#endif
+ }
+
+ internal IntPtr DynamicGcStaticsData
+ {
+ get
+ {
+ Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicGcStatics);
+ fixed (MethodTable* pThis = &this)
+ {
+ return *(IntPtr*)((byte*)pThis + cbOffset);
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicGcStatics);
+ fixed (MethodTable* pThis = &this)
+ {
+ *(IntPtr*)((byte*)pThis + cbOffset) = value;
+ }
+ }
+#endif
+ }
+
+ internal IntPtr DynamicNonGcStaticsData
+ {
+ get
+ {
+ Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicNonGcStatics);
+ fixed (MethodTable* pThis = &this)
+ {
+ return *(IntPtr*)((byte*)pThis + cbOffset);
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert((RareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicNonGcStatics);
+ fixed (MethodTable* pThis = &this)
+ {
+ *(IntPtr*)((byte*)pThis + cbOffset) = value;
+ }
+ }
+#endif
+ }
+
+ internal DynamicModule* DynamicModule
+ {
+ get
+ {
+ if ((RareFlags & EETypeRareFlags.HasDynamicModuleFlag) != 0)
+ {
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicModule);
+ fixed (MethodTable* pThis = &this)
+ {
+ return *(DynamicModule**)((byte*)pThis + cbOffset);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(RareFlags.HasFlag(EETypeRareFlags.HasDynamicModuleFlag));
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_DynamicModule);
+ fixed (MethodTable* pThis = &this)
+ {
+ *(DynamicModule**)((byte*)pThis + cbOffset) = value;
+ }
+ }
+#endif
+ }
+
+ internal TypeManagerHandle TypeManager
+ {
+ get
+ {
+ IntPtr typeManagerIndirection;
+ if (IsDynamicType || !SupportsRelativePointers)
+ typeManagerIndirection = GetField(EETypeField.ETF_TypeManagerIndirection).Value;
+ else
+ typeManagerIndirection = GetField(EETypeField.ETF_TypeManagerIndirection).Value;
+
+ return *(TypeManagerHandle*)typeManagerIndirection;
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ internal IntPtr PointerToTypeManager
+ {
+ get
+ {
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_TypeManagerIndirection);
+ // This is always a pointer to a pointer to a type manager
+ return (IntPtr)(*(TypeManagerHandle**)((byte*)Unsafe.AsPointer(ref this) + cbOffset));
+ }
+ set
+ {
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_TypeManagerIndirection);
+ // This is always a pointer to a pointer to a type manager
+ *(TypeManagerHandle**)((byte*)Unsafe.AsPointer(ref this) + cbOffset) = (TypeManagerHandle*)value;
+ }
+ }
+#endif
+
+ ///
+ /// Gets a pointer to a segment of writable memory associated with this MethodTable.
+ /// The purpose of the segment is controlled by the class library. The runtime doesn't
+ /// use this memory for any purpose.
+ ///
+ internal IntPtr WritableData
+ {
+ get
+ {
+ Debug.Assert(SupportsWritableData);
+
+ uint offset = GetFieldOffset(EETypeField.ETF_WritableData);
+
+ if (!IsDynamicType)
+ return GetField(offset).Value;
+ else
+ return GetField(offset).Value;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ Debug.Assert(IsDynamicType && SupportsWritableData);
+
+ uint cbOffset = GetFieldOffset(EETypeField.ETF_WritableData);
+ *(IntPtr*)((byte*)Unsafe.AsPointer(ref this) + cbOffset) = value;
+ }
+#endif
+ }
+
+ internal unsafe EETypeRareFlags RareFlags
+ {
+ get
+ {
+ // If there are no optional fields then none of the rare flags have been set.
+ // Get the flags from the optional fields. The default is zero if that particular field was not included.
+ return HasOptionalFields ? (EETypeRareFlags)OptionalFieldsReader.GetInlineField(OptionalFieldsPtr, EETypeOptionalFieldTag.RareFlags, 0) : 0;
+ }
+ }
+
+ internal int FieldAlignmentRequirement
+ {
+ get
+ {
+ byte* optionalFields = OptionalFieldsPtr;
+
+ // If there are no optional fields then the alignment must have been the default, IntPtr.Size.
+ // (This happens for all reference types, and for valuetypes with default alignment and no padding)
+ if (optionalFields == null)
+ return IntPtr.Size;
+
+ // Get the value from the optional fields. The default is zero if that particular field was not included.
+ // The low bits of this field is the ValueType field padding, the rest of the value is the alignment if present
+ uint alignmentValue = (OptionalFieldsReader.GetInlineField(optionalFields, EETypeOptionalFieldTag.ValueTypeFieldPadding, 0) & ValueTypePaddingAlignmentMask) >> ValueTypePaddingAlignmentShift;
+
+ // Alignment is stored as 1 + the log base 2 of the alignment, except a 0 indicates standard pointer alignment.
+ if (alignmentValue == 0)
+ return IntPtr.Size;
+ else
+ return 1 << ((int)alignmentValue - 1);
+ }
+ }
+
+ internal EETypeElementType ElementType
+ {
+ get
+ {
+ return (EETypeElementType)((_usFlags & (ushort)EETypeFlags.ElementTypeMask) >> (ushort)EETypeFlags.ElementTypeShift);
+ }
+ }
+
+ public bool HasCctor
+ {
+ get
+ {
+ return (RareFlags & EETypeRareFlags.HasCctorFlag) != 0;
+ }
+ }
+
+ public uint GetFieldOffset(EETypeField eField)
+ {
+ // First part of MethodTable consists of the fixed portion followed by the vtable.
+ uint cbOffset = (uint)(sizeof(MethodTable) + (IntPtr.Size * _usNumVtableSlots));
+
+ // Then we have the interface map.
+ if (eField == EETypeField.ETF_InterfaceMap)
+ {
+ Debug.Assert(NumInterfaces > 0);
+ return cbOffset;
+ }
+ cbOffset += (uint)(sizeof(EEInterfaceInfo) * NumInterfaces);
+
+ uint relativeOrFullPointerOffset = (IsDynamicType || !SupportsRelativePointers ? (uint)IntPtr.Size : 4);
+
+ // Followed by the type manager indirection cell.
+ if (eField == EETypeField.ETF_TypeManagerIndirection)
+ {
+ return cbOffset;
+ }
+ cbOffset += relativeOrFullPointerOffset;
+
+ // Followed by writable data.
+ if (SupportsWritableData)
+ {
+ if (eField == EETypeField.ETF_WritableData)
+ {
+ return cbOffset;
+ }
+ cbOffset += relativeOrFullPointerOffset;
+ }
+
+ // Followed by the pointer to the finalizer method.
+ if (eField == EETypeField.ETF_Finalizer)
+ {
+ Debug.Assert(IsFinalizable);
+ return cbOffset;
+ }
+ if (IsFinalizable)
+ cbOffset += relativeOrFullPointerOffset;
+
+ // Followed by the pointer to the optional fields.
+ if (eField == EETypeField.ETF_OptionalFieldsPtr)
+ {
+ Debug.Assert(HasOptionalFields);
+ return cbOffset;
+ }
+ if (HasOptionalFields)
+ cbOffset += relativeOrFullPointerOffset;
+
+ // Followed by the pointer to the sealed virtual slots
+ if (eField == EETypeField.ETF_SealedVirtualSlots)
+ return cbOffset;
+
+ EETypeRareFlags rareFlags = RareFlags;
+
+ // in the case of sealed vtable entries on static types, we have a UInt sized relative pointer
+ if ((rareFlags & EETypeRareFlags.HasSealedVTableEntriesFlag) != 0)
+ cbOffset += relativeOrFullPointerOffset;
+
+ if (eField == EETypeField.ETF_DynamicDispatchMap)
+ {
+ Debug.Assert(IsDynamicType);
+ return cbOffset;
+ }
+ if ((rareFlags & EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag) != 0)
+ cbOffset += (uint)IntPtr.Size;
+
+ if (eField == EETypeField.ETF_GenericDefinition)
+ {
+ Debug.Assert(IsGeneric);
+ return cbOffset;
+ }
+ if (IsGeneric)
+ {
+ cbOffset += relativeOrFullPointerOffset;
+ }
+
+ if (eField == EETypeField.ETF_GenericComposition)
+ {
+ Debug.Assert(IsGeneric);
+ return cbOffset;
+ }
+ if (IsGeneric)
+ {
+ cbOffset += relativeOrFullPointerOffset;
+ }
+
+ if (eField == EETypeField.ETF_DynamicModule)
+ {
+ return cbOffset;
+ }
+
+ if ((rareFlags & EETypeRareFlags.HasDynamicModuleFlag) != 0)
+ cbOffset += (uint)IntPtr.Size;
+
+ if (eField == EETypeField.ETF_DynamicTemplateType)
+ {
+ Debug.Assert(IsDynamicType);
+ return cbOffset;
+ }
+ if (IsDynamicType)
+ cbOffset += (uint)IntPtr.Size;
+
+ if (eField == EETypeField.ETF_DynamicGcStatics)
+ {
+ Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0);
+ return cbOffset;
+ }
+ if ((rareFlags & EETypeRareFlags.IsDynamicTypeWithGcStatics) != 0)
+ cbOffset += (uint)IntPtr.Size;
+
+ if (eField == EETypeField.ETF_DynamicNonGcStatics)
+ {
+ Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0);
+ return cbOffset;
+ }
+ if ((rareFlags & EETypeRareFlags.IsDynamicTypeWithNonGcStatics) != 0)
+ cbOffset += (uint)IntPtr.Size;
+
+ if (eField == EETypeField.ETF_DynamicThreadStaticOffset)
+ {
+ Debug.Assert((rareFlags & EETypeRareFlags.IsDynamicTypeWithThreadStatics) != 0);
+ return cbOffset;
+ }
+ if ((rareFlags & EETypeRareFlags.IsDynamicTypeWithThreadStatics) != 0)
+ cbOffset += 4;
+
+ Debug.Assert(false, "Unknown MethodTable field type");
+ return 0;
+ }
+
+ public ref T GetField(EETypeField eField)
+ {
+ return ref Unsafe.As(ref *((byte*)Unsafe.AsPointer(ref this) + GetFieldOffset(eField)));
+ }
+
+ public ref T GetField(uint offset)
+ {
+ return ref Unsafe.As(ref *((byte*)Unsafe.AsPointer(ref this) + offset));
+ }
+
+#if TYPE_LOADER_IMPLEMENTATION
+ internal static uint GetSizeofEEType(
+ ushort cVirtuals,
+ ushort cInterfaces,
+ bool fHasFinalizer,
+ bool fRequiresOptionalFields,
+ bool fHasSealedVirtuals,
+ bool fHasGenericInfo,
+ bool fHasNonGcStatics,
+ bool fHasGcStatics,
+ bool fHasThreadStatics)
+ {
+ return (uint)(sizeof(MethodTable) +
+ (IntPtr.Size * cVirtuals) +
+ (sizeof(EEInterfaceInfo) * cInterfaces) +
+ sizeof(IntPtr) + // TypeManager
+ (SupportsWritableData ? sizeof(IntPtr) : 0) + // WritableData
+ (fHasFinalizer ? sizeof(UIntPtr) : 0) +
+ (fRequiresOptionalFields ? sizeof(IntPtr) : 0) +
+ (fHasSealedVirtuals ? sizeof(IntPtr) : 0) +
+ (fHasGenericInfo ? sizeof(IntPtr)*2 : 0) + // pointers to GenericDefinition and GenericComposition
+ (fHasNonGcStatics ? sizeof(IntPtr) : 0) + // pointer to data
+ (fHasGcStatics ? sizeof(IntPtr) : 0) + // pointer to data
+ (fHasThreadStatics ? sizeof(uint) : 0)); // tls offset
+ }
+#endif
+ }
+
+ // Wrapper around MethodTable pointers that may be indirected through the IAT if their low bit is set.
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct EETypeRef
+ {
+ private byte* _value;
+
+ public MethodTable* Value
+ {
+ get
+ {
+ if (((int)_value & IndirectionConstants.IndirectionCellPointer) == 0)
+ return (MethodTable*)_value;
+ return *(MethodTable**)(_value - IndirectionConstants.IndirectionCellPointer);
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _value = (byte*)value;
+ }
+#endif
+ }
+ }
+
+ // Wrapper around pointers
+ [StructLayout(LayoutKind.Sequential)]
+ internal readonly struct Pointer
+ {
+ private readonly IntPtr _value;
+
+ public IntPtr Value
+ {
+ get
+ {
+ return _value;
+ }
+ }
+ }
+
+ // Wrapper around pointers
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe readonly struct Pointer where T : unmanaged
+ {
+ private readonly T* _value;
+
+ public T* Value
+ {
+ get
+ {
+ return _value;
+ }
+ }
+ }
+
+ // Wrapper around pointers that might be indirected through IAT
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe readonly struct IatAwarePointer where T : unmanaged
+ {
+ private readonly T* _value;
+
+ public T* Value
+ {
+ get
+ {
+ if (((int)_value & IndirectionConstants.IndirectionCellPointer) == 0)
+ return _value;
+ return *(T**)((byte*)_value - IndirectionConstants.IndirectionCellPointer);
+ }
+ }
+ }
+
+ // Wrapper around relative pointers
+ [StructLayout(LayoutKind.Sequential)]
+ internal readonly struct RelativePointer
+ {
+ private readonly int _value;
+
+ public unsafe IntPtr Value
+ {
+ get
+ {
+ return (IntPtr)((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in _value)) + _value);
+ }
+ }
+ }
+
+ // Wrapper around relative pointers
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe readonly struct RelativePointer where T : unmanaged
+ {
+ private readonly int _value;
+
+ public T* Value
+ {
+ get
+ {
+ return (T*)((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in _value)) + _value);
+ }
+ }
+ }
+
+ // Wrapper around relative pointers that might be indirected through IAT
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe readonly struct IatAwareRelativePointer where T : unmanaged
+ {
+ private readonly int _value;
+
+ public T* Value
+ {
+ get
+ {
+ if ((_value & IndirectionConstants.IndirectionCellPointer) == 0)
+ {
+ return (T*)((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in _value)) + _value);
+ }
+ else
+ {
+ return *(T**)((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in _value)) + (_value & ~IndirectionConstants.IndirectionCellPointer));
+ }
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct DynamicModule
+ {
+ // Size field used to indicate the number of bytes of this structure that are defined in Runtime Known ways
+ // This is used to drive versioning of this field
+ private int _cbSize;
+
+ // Pointer to interface dispatch resolver that works off of a type/slot pair
+ // This is a function pointer with the following signature IntPtr()(MethodTable* targetType, MethodTable* interfaceType, ushort slot)
+ private delegate* _dynamicTypeSlotDispatchResolve;
+
+ // Starting address for the the binary module corresponding to this dynamic module.
+ private delegate* _getRuntimeException;
+
+#if TYPE_LOADER_IMPLEMENTATION
+ public int CbSize
+ {
+ get
+ {
+ return _cbSize;
+ }
+ set
+ {
+ _cbSize = value;
+ }
+ }
+#endif
+
+ public delegate* DynamicTypeSlotDispatchResolve
+ {
+ get
+ {
+ if (_cbSize >= sizeof(IntPtr) * 2)
+ {
+ return _dynamicTypeSlotDispatchResolve;
+ }
+ else
+ {
+ return null;
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _dynamicTypeSlotDispatchResolve = value;
+ }
+#endif
+ }
+
+ public delegate* GetRuntimeException
+ {
+ get
+ {
+ if (_cbSize >= sizeof(IntPtr) * 3)
+ {
+ return _getRuntimeException;
+ }
+ else
+ {
+ return null;
+ }
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _getRuntimeException = value;
+ }
+#endif
+ }
+
+ /////////////////////// END OF FIELDS KNOWN TO THE MRT RUNTIME ////////////////////////
+#if TYPE_LOADER_IMPLEMENTATION
+ public static readonly int DynamicModuleSize = IntPtr.Size * 3; // We have three fields here.
+
+ // We can put non-low level runtime fields that are module level, that need quick access from a type here
+ // For instance, we may choose to put a pointer to the metadata reader or the like here in the future.
+#endif
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/TransitionBlock.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TransitionBlock.cs
new file mode 100644
index 00000000000000..909514e070b122
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TransitionBlock.cs
@@ -0,0 +1,468 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+// This file is a line by line port of callingconvention.h from the CLR with the intention that we may wish to merge
+// changes from the CLR in at a later time. As such, the normal coding conventions are ignored.
+//
+
+//
+#if TARGET_ARM
+#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
+#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
+#define ENREGISTERED_RETURNTYPE_MAXSIZE
+#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
+#define FEATURE_HFA
+#elif TARGET_ARM64
+#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
+#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
+#define ENREGISTERED_RETURNTYPE_MAXSIZE
+#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
+#define ENREGISTERED_PARAMTYPE_MAXSIZE
+#define FEATURE_HFA
+#elif TARGET_X86
+#define ENREGISTERED_RETURNTYPE_MAXSIZE
+#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
+#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
+#elif TARGET_AMD64
+#if TARGET_UNIX
+#define UNIX_AMD64_ABI
+#define CALLDESCR_ARGREGS // CallDescrWorker has ArgumentRegister parameter
+#else
+#endif
+#define CALLDESCR_FPARGREGS // CallDescrWorker has FloatArgumentRegisters parameter
+#define ENREGISTERED_RETURNTYPE_MAXSIZE
+#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
+#define ENREGISTERED_PARAMTYPE_MAXSIZE
+#elif TARGET_WASM
+#else
+#error Unknown architecture!
+#endif
+
+// Provides an abstraction over platform specific calling conventions (specifically, the calling convention
+// utilized by the JIT on that platform). The caller enumerates each argument of a signature in turn, and is
+// provided with information mapping that argument into registers and/or stack locations.
+
+using System;
+
+namespace Internal.Runtime
+{
+#if TARGET_AMD64
+#pragma warning disable 0169
+#if UNIX_AMD64_ABI
+ struct ReturnBlock
+ {
+ IntPtr returnValue;
+ IntPtr returnValue2;
+ }
+
+ struct ArgumentRegisters
+ {
+ IntPtr rdi;
+ IntPtr rsi;
+ IntPtr rdx;
+ IntPtr rcx;
+ IntPtr r8;
+ IntPtr r9;
+ }
+#else // UNIX_AMD64_ABI
+ struct ReturnBlock
+ {
+ IntPtr returnValue;
+ }
+
+ struct ArgumentRegisters
+ {
+ IntPtr rdx;
+ IntPtr rcx;
+ IntPtr r8;
+ IntPtr r9;
+ }
+#endif // UNIX_AMD64_ABI
+#pragma warning restore 0169
+
+#pragma warning disable 0169
+ struct M128A
+ {
+ IntPtr a;
+ IntPtr b;
+ }
+ struct FloatArgumentRegisters
+ {
+ M128A d0;
+ M128A d1;
+ M128A d2;
+ M128A d3;
+#if UNIX_AMD64_ABI
+ M128A d4;
+ M128A d5;
+ M128A d6;
+ M128A d7;
+#endif
+ }
+#pragma warning restore 0169
+
+ struct ArchitectureConstants
+ {
+ // To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
+ public const int MAX_ARG_SIZE = 0xFFFFFF;
+
+#if UNIX_AMD64_ABI
+ public const int NUM_ARGUMENT_REGISTERS = 6;
+#else
+ public const int NUM_ARGUMENT_REGISTERS = 4;
+#endif
+ public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 8;
+ public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 8;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 8;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
+ public const int ENREGISTERED_PARAMTYPE_MAXSIZE = 8;
+ public const int STACK_ELEM_SIZE = 8;
+ public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
+ }
+#elif TARGET_ARM64
+#pragma warning disable 0169
+ struct ReturnBlock
+ {
+ IntPtr returnValue;
+ IntPtr returnValue2;
+ IntPtr returnValue3;
+ IntPtr returnValue4;
+ }
+
+ struct ArgumentRegisters
+ {
+ IntPtr x0;
+ IntPtr x1;
+ IntPtr x2;
+ IntPtr x3;
+ IntPtr x4;
+ IntPtr x5;
+ IntPtr x6;
+ IntPtr x7;
+ IntPtr x8;
+ public static unsafe int GetOffsetOfx8()
+ {
+ return sizeof(IntPtr) * 8;
+ }
+ }
+#pragma warning restore 0169
+
+#pragma warning disable 0169
+ struct FloatArgumentRegisters
+ {
+ double d0;
+ double d1;
+ double d2;
+ double d3;
+ double d4;
+ double d5;
+ double d6;
+ double d7;
+ }
+#pragma warning restore 0169
+
+ struct ArchitectureConstants
+ {
+ // To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
+ public const int MAX_ARG_SIZE = 0xFFFFFF;
+
+ public const int NUM_ARGUMENT_REGISTERS = 8;
+ public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 8;
+ public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 32; // bytes (four FP registers: d0,d1,d2 and d3)
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 16; // bytes (two int registers: x0 and x1)
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
+ public const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16; // bytes (max value type size that can be passed by value)
+ public const int STACK_ELEM_SIZE = 8;
+ public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
+ }
+#elif TARGET_X86
+#pragma warning disable 0169, 0649
+ struct ReturnBlock
+ {
+ public IntPtr returnValue;
+ public IntPtr returnValue2;
+ }
+
+ struct ArgumentRegisters
+ {
+ public IntPtr edx;
+ public static unsafe int GetOffsetOfEdx()
+ {
+ return 0;
+ }
+ public IntPtr ecx;
+ public static unsafe int GetOffsetOfEcx()
+ {
+ return sizeof(IntPtr);
+ }
+ }
+ // This struct isn't used by x86, but exists for compatibility with the definition of the CallDescrData struct
+ struct FloatArgumentRegisters
+ {
+ }
+#pragma warning restore 0169, 0649
+
+ struct ArchitectureConstants
+ {
+ // To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
+ public const int MAX_ARG_SIZE = 0xFFFFFF;
+
+ public const int NUM_ARGUMENT_REGISTERS = 2;
+ public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 4;
+ public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 8;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 4;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 4;
+ public const int STACK_ELEM_SIZE = 4;
+ public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
+ }
+#elif TARGET_ARM
+#pragma warning disable 0169
+ struct ReturnBlock
+ {
+ IntPtr returnValue;
+ IntPtr returnValue2;
+ IntPtr returnValue3;
+ IntPtr returnValue4;
+ IntPtr returnValue5;
+ IntPtr returnValue6;
+ IntPtr returnValue7;
+ IntPtr returnValue8;
+ }
+
+ struct ArgumentRegisters
+ {
+ IntPtr r0;
+ IntPtr r1;
+ IntPtr r2;
+ IntPtr r3;
+ }
+
+ struct FloatArgumentRegisters
+ {
+ double d0;
+ double d1;
+ double d2;
+ double d3;
+ double d4;
+ double d5;
+ double d6;
+ double d7;
+ }
+#pragma warning restore 0169
+
+ struct ArchitectureConstants
+ {
+ // To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
+ public const int MAX_ARG_SIZE = 0xFFFFFF;
+
+ public const int NUM_ARGUMENT_REGISTERS = 4;
+ public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 4;
+ public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 32;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 4;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
+ public const int STACK_ELEM_SIZE = 4;
+ public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
+ }
+
+#elif TARGET_WASM
+#pragma warning disable 0169
+ struct ReturnBlock
+ {
+ IntPtr returnValue;
+ }
+
+ struct ArgumentRegisters
+ {
+ // No registers on WASM
+ }
+
+ struct FloatArgumentRegisters
+ {
+ // No registers on WASM
+ }
+#pragma warning restore 0169
+
+ struct ArchitectureConstants
+ {
+ // To avoid corner case bugs, limit maximum size of the arguments with sufficient margin
+ public const int MAX_ARG_SIZE = 0xFFFFFF;
+
+ public const int NUM_ARGUMENT_REGISTERS = 0;
+ public const int ARGUMENTREGISTERS_SIZE = NUM_ARGUMENT_REGISTERS * 4;
+ public const int ENREGISTERED_RETURNTYPE_MAXSIZE = 32;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE = 4;
+ public const int ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE_PRIMITIVE = 8;
+ public const int STACK_ELEM_SIZE = 4;
+ public static int StackElemSize(int size) { return (((size) + STACK_ELEM_SIZE - 1) & ~(STACK_ELEM_SIZE - 1)); }
+ }
+#endif
+
+ //
+ // TransitionBlock is layout of stack frame of method call, saved argument registers and saved callee saved registers. Even though not
+ // all fields are used all the time, we use uniform form for simplicity.
+ //
+ internal struct TransitionBlock
+ {
+#pragma warning disable 0169,0649
+
+#if TARGET_X86
+ public ArgumentRegisters m_argumentRegisters;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return 0;
+ }
+ public ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return sizeof(ArgumentRegisters);
+ }
+ IntPtr m_ebp;
+ IntPtr m_ReturnAddress;
+#elif TARGET_AMD64
+
+#if UNIX_AMD64_ABI
+ public ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return 0;
+ }
+
+ public ArgumentRegisters m_argumentRegisters;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return sizeof(ReturnBlock);
+ }
+
+ IntPtr m_alignmentPadding;
+ IntPtr m_ReturnAddress;
+#else // UNIX_AMD64_ABI
+ IntPtr m_returnBlockPadding;
+ ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return sizeof(IntPtr);
+ }
+ IntPtr m_alignmentPadding;
+ IntPtr m_ReturnAddress;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return sizeof(TransitionBlock);
+ }
+#endif // UNIX_AMD64_ABI
+
+#elif TARGET_ARM
+ public ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return 0;
+ }
+
+ public ArgumentRegisters m_argumentRegisters;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return sizeof(ReturnBlock);
+ }
+#elif TARGET_ARM64
+ public ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return 0;
+ }
+
+ public ArgumentRegisters m_argumentRegisters;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return sizeof(ReturnBlock);
+ }
+
+ public IntPtr m_alignmentPad;
+#elif TARGET_WASM
+ public ReturnBlock m_returnBlock;
+ public static unsafe int GetOffsetOfReturnValuesBlock()
+ {
+ return 0;
+ }
+
+ public ArgumentRegisters m_argumentRegisters;
+ public static unsafe int GetOffsetOfArgumentRegisters()
+ {
+ return sizeof(ReturnBlock);
+ }
+#else
+#error Portability problem
+#endif
+#pragma warning restore 0169, 0649
+
+ // The transition block should define everything pushed by callee. The code assumes in number of places that
+ // end of the transition block is caller's stack pointer.
+
+ public static unsafe byte GetOffsetOfArgs()
+ {
+ return (byte)sizeof(TransitionBlock);
+ }
+
+
+ public static bool IsStackArgumentOffset(int offset)
+ {
+ int ofsArgRegs = GetOffsetOfArgumentRegisters();
+
+ return offset >= (int)(ofsArgRegs + ArchitectureConstants.ARGUMENTREGISTERS_SIZE);
+ }
+
+ public static bool IsArgumentRegisterOffset(int offset)
+ {
+ int ofsArgRegs = GetOffsetOfArgumentRegisters();
+
+ return offset >= ofsArgRegs && offset < (int)(ofsArgRegs + ArchitectureConstants.ARGUMENTREGISTERS_SIZE);
+ }
+
+#if !TARGET_X86
+ public static unsafe int GetArgumentIndexFromOffset(int offset)
+ {
+ return ((offset - GetOffsetOfArgumentRegisters()) / IntPtr.Size);
+ }
+
+ public static int GetStackArgumentIndexFromOffset(int offset)
+ {
+ return (offset - GetOffsetOfArgs()) / ArchitectureConstants.STACK_ELEM_SIZE;
+ }
+#endif
+
+#if CALLDESCR_FPARGREGS
+ public static bool IsFloatArgumentRegisterOffset(int offset)
+ {
+ return offset < 0;
+ }
+
+ public static int GetOffsetOfFloatArgumentRegisters()
+ {
+ return -GetNegSpaceSize();
+ }
+#endif
+
+ public static unsafe int GetNegSpaceSize()
+ {
+ int negSpaceSize = 0;
+#if CALLDESCR_FPARGREGS
+ negSpaceSize += sizeof(FloatArgumentRegisters);
+#endif
+ return negSpaceSize;
+ }
+
+ public static int GetThisOffset()
+ {
+ // This pointer is in the first argument register by default
+ int ret = TransitionBlock.GetOffsetOfArgumentRegisters();
+
+#if TARGET_X86
+ // x86 is special as always
+ ret += ArgumentRegisters.GetOffsetOfEcx();
+#endif
+
+ return ret;
+ }
+
+ public const int InvalidOffset = -1;
+ };
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.Equality.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.Equality.cs
new file mode 100644
index 00000000000000..39b6afdebd107c
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.Equality.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace Internal.Runtime
+{
+ public unsafe partial struct TypeManagerHandle : IEquatable
+ {
+ public static bool operator ==(TypeManagerHandle left, TypeManagerHandle right)
+ {
+ return left._handleValue == right._handleValue;
+ }
+
+ public static bool operator !=(TypeManagerHandle left, TypeManagerHandle right)
+ {
+ return left._handleValue != right._handleValue;
+ }
+
+ public override int GetHashCode()
+ {
+ return ((IntPtr)_handleValue).GetHashCode();
+ }
+
+ public override bool Equals(object o)
+ {
+ if (!(o is TypeManagerHandle))
+ return false;
+
+ return _handleValue == ((TypeManagerHandle)o)._handleValue;
+ }
+
+ public bool Equals(TypeManagerHandle other)
+ {
+ return _handleValue == other._handleValue;
+ }
+
+ public string LowLevelToString()
+ {
+ return ((IntPtr)_handleValue).LowLevelToString();
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.cs
new file mode 100644
index 00000000000000..9780acd39f72a9
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeManagerHandle.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Internal.Runtime
+{
+ ///
+ /// TypeManagerHandle represents an AOT module in MRT based runtimes.
+ /// These handles are a pointer to a TypeManager
+ ///
+ public unsafe partial struct TypeManagerHandle
+ {
+ private TypeManager* _handleValue;
+
+ // This is a partial definition of the TypeManager struct which is defined in TypeManager.h
+ [StructLayout(LayoutKind.Sequential)]
+ private struct TypeManager
+ {
+ public IntPtr OsHandle;
+ public IntPtr ReadyToRunHeader;
+ public IntPtr DispatchMap;
+ }
+
+ public TypeManagerHandle(IntPtr handleValue)
+ {
+ _handleValue = (TypeManager*)handleValue;
+ }
+
+ public IntPtr GetIntPtrUNSAFE()
+ {
+ return (IntPtr)_handleValue;
+ }
+
+ public bool IsNull
+ {
+ get
+ {
+ return _handleValue == null;
+ }
+ }
+
+ public unsafe IntPtr OsModuleBase
+ {
+ get
+ {
+ return _handleValue->OsHandle;
+ }
+ }
+
+ public unsafe IntPtr DispatchMap
+ {
+ get
+ {
+ return _handleValue->DispatchMap;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifier.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifier.cs
new file mode 100644
index 00000000000000..888522ccbea484
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifier.cs
@@ -0,0 +1,310 @@
+// 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.Threading;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace System.Collections.Concurrent
+{
+ // Abstract base for a thread-safe dictionary mapping a set of keys (K) to values (V).
+ //
+ // To create an actual dictionary, subclass this type and override the protected Factory method
+ // to instantiate values (V) for the "Add" case.
+ //
+ // The key must be of a type that implements IEquatable. The unifier calls IEquality.Equals()
+ // and Object.GetHashCode() on the keys.
+ //
+ // Deadlock risks:
+ // - Keys may be tested for equality and asked to compute their hashcode while the unifier
+ // holds its lock. Thus these operations must be written carefully to avoid deadlocks and
+ // reentrancy in to the table.
+ //
+ // - The Factory method will never be called inside the unifier lock. If two threads race to
+ // enter a value for the same key, the Factory() may get invoked twice for the same key - one
+ // of them will "win" the race and its result entered into the dictionary - other gets thrown away.
+ //
+ // Notes:
+ // - This class is used to look up types when GetType() or typeof() is invoked.
+ // That means that this class itself cannot do or call anything that does these
+ // things.
+ //
+ // - For this reason, it chooses not to mimic the official ConcurrentDictionary class
+ // (I don't even want to risk using delegates.) Even the LowLevel versions of these
+ // general utility classes may not be low-level enough for this class's purpose.
+ //
+ // Thread safety guarantees:
+ //
+ // ConcurrentUnifier is fully thread-safe and requires no
+ // additional locking to be done by callers.
+ //
+ // Performance characteristics:
+ //
+ // ConcurrentUnifier will not block a reader, even while
+ // the table is being written. Only one writer is allowed at a time;
+ // ConcurrentUnifier handles the synchronization that ensures this.
+ //
+ // Safety for concurrent readers is ensured as follows:
+ //
+ // Each hash bucket is maintained as a stack. Inserts are done under
+ // a lock; the entry is filled out completely, then "published" by a
+ // single write to the top of the bucket. This ensures that a reader
+ // will see a valid snapshot of the bucket, once it has read the head.
+ //
+ // On resize, we allocate an entirely new table, rather than resizing
+ // in place. We fill in the new table completely, under the lock,
+ // then "publish" it with a single write. Any reader that races with
+ // this will either see the old table or the new one; each will contain
+ // the same data.
+ //
+ internal abstract class ConcurrentUnifier
+ where K : IEquatable
+ where V : class
+ {
+ protected ConcurrentUnifier()
+ {
+ _lock = new Lock();
+ _container = new Container(this);
+ }
+
+ //
+ // Retrieve the *unique* value for a given key. If the key was previously not entered into the dictionary,
+ // this method invokes the overridable Factory() method to create the new value. The Factory() method is
+ // invoked outside of any locks. If two threads race to enter a value for the same key, the Factory()
+ // may get invoked twice for the same key - one of them will "win" the race and its result entered into the
+ // dictionary - other gets thrown away.
+ //
+ public V GetOrAdd(K key)
+ {
+ Debug.Assert(key != null);
+ Debug.Assert(!_lock.IsAcquired, "GetOrAdd called while lock already acquired. A possible cause of this is an Equals or GetHashCode method that causes reentrancy in the table.");
+
+ int hashCode = key.GetHashCode();
+ V value;
+ bool found = _container.TryGetValue(key, hashCode, out value);
+#if DEBUG
+ {
+ V checkedValue;
+ bool checkedFound;
+ // In debug builds, always exercise a locked TryGet (this is a good way to detect deadlock/reentrancy through Equals/GetHashCode()).
+ using (LockHolder.Hold(_lock))
+ {
+ _container.VerifyUnifierConsistency();
+ int h = key.GetHashCode();
+ checkedFound = _container.TryGetValue(key, h, out checkedValue);
+ }
+
+ if (found)
+ {
+ // State of a key must never go from found to not found, and only one value may exist per key.
+ Debug.Assert(checkedFound);
+ if (default(V) == null) // No good way to do the "only one value" check for value types.
+ Debug.Assert(object.ReferenceEquals(checkedValue, value));
+ }
+ }
+#endif //DEBUG
+ if (found)
+ return value;
+
+ value = this.Factory(key);
+
+ using (LockHolder.Hold(_lock))
+ {
+ V heyIWasHereFirst;
+ if (_container.TryGetValue(key, hashCode, out heyIWasHereFirst))
+ return heyIWasHereFirst;
+ if (!_container.HasCapacity)
+ _container.Resize(); // This overwrites the _container field.
+ _container.Add(key, hashCode, value);
+ return value;
+ }
+ }
+
+ protected abstract V Factory(K key);
+
+ private volatile Container _container;
+ private readonly Lock _lock;
+
+ private sealed class Container
+ {
+ public Container(ConcurrentUnifier owner)
+ {
+ // Note: This could be done by calling Resize()'s logic but we cannot safely do that as this code path is reached
+ // during class construction time and Resize() pulls in enough stuff that we get cyclic cctor warnings from the build.
+ _buckets = new int[_initialCapacity];
+ for (int i = 0; i < _initialCapacity; i++)
+ _buckets[i] = -1;
+ _entries = new Entry[_initialCapacity];
+ _nextFreeEntry = 0;
+ _owner = owner;
+ }
+
+ private Container(ConcurrentUnifier owner, int[] buckets, Entry[] entries, int nextFreeEntry)
+ {
+ _buckets = buckets;
+ _entries = entries;
+ _nextFreeEntry = nextFreeEntry;
+ _owner = owner;
+ }
+
+ public bool TryGetValue(K key, int hashCode, out V value)
+ {
+ // Lock acquistion NOT required (but lock inacquisition NOT guaranteed either.)
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+ int i = Volatile.Read(ref _buckets[bucket]);
+ while (i != -1)
+ {
+ if (key.Equals(_entries[i]._key))
+ {
+ value = _entries[i]._value;
+ return true;
+ }
+ i = _entries[i]._next;
+ }
+
+ value = default(V);
+ return false;
+ }
+
+ public void Add(K key, int hashCode, V value)
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+
+ int newEntryIdx = _nextFreeEntry;
+ _entries[newEntryIdx]._key = key;
+ _entries[newEntryIdx]._value = value;
+ _entries[newEntryIdx]._hashCode = hashCode;
+ _entries[newEntryIdx]._next = _buckets[bucket];
+
+ _nextFreeEntry++;
+
+ // The line that atomically adds the new key/value pair. If the thread is killed before this line executes but after
+ // we've incremented _nextFreeEntry, this entry is harmlessly leaked until the next resize.
+ Volatile.Write(ref _buckets[bucket], newEntryIdx);
+
+ VerifyUnifierConsistency();
+ }
+
+ public bool HasCapacity
+ {
+ get
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+ return _nextFreeEntry != _entries.Length;
+ }
+ }
+
+ public void Resize()
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ int newSize = HashHelpers.GetPrime(_buckets.Length * 2);
+#if DEBUG
+ newSize = _buckets.Length + 3;
+#endif
+ if (newSize <= _nextFreeEntry)
+ throw new OutOfMemoryException();
+
+ Entry[] newEntries = new Entry[newSize];
+ int[] newBuckets = new int[newSize];
+ for (int i = 0; i < newSize; i++)
+ newBuckets[i] = -1;
+
+ // Note that we walk the bucket chains rather than iterating over _entries. This is because we allow for the possibility
+ // of abandoned entries (with undefined contents) if a thread is killed between allocating an entry and linking it onto the
+ // bucket chain.
+ int newNextFreeEntry = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ for (int entry = _buckets[bucket]; entry != -1; entry = _entries[entry]._next)
+ {
+ newEntries[newNextFreeEntry]._key = _entries[entry]._key;
+ newEntries[newNextFreeEntry]._value = _entries[entry]._value;
+ newEntries[newNextFreeEntry]._hashCode = _entries[entry]._hashCode;
+ int newBucket = ComputeBucket(newEntries[newNextFreeEntry]._hashCode, newSize);
+ newEntries[newNextFreeEntry]._next = newBuckets[newBucket];
+ newBuckets[newBucket] = newNextFreeEntry;
+ newNextFreeEntry++;
+ }
+ }
+
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ Debug.Assert(newNextFreeEntry <= _nextFreeEntry);
+
+ // The line that atomically installs the resize. If this thread is killed before this point,
+ // the table remains full and the next guy attempting an add will have to redo the resize.
+ _owner._container = new Container(_owner, newBuckets, newEntries, newNextFreeEntry);
+
+ _owner._container.VerifyUnifierConsistency();
+ }
+
+ private static int ComputeBucket(int hashCode, int numBuckets)
+ {
+ int bucket = (hashCode & 0x7fffffff) % numBuckets;
+ return bucket;
+ }
+
+ [Conditional("DEBUG")]
+ public void VerifyUnifierConsistency()
+ {
+#if DEBUG
+ // There's a point at which this check becomes gluttonous, even by checked build standards...
+ if (_nextFreeEntry >= 5000 && (0 != (_nextFreeEntry % 100)))
+ return;
+
+ Debug.Assert(_owner._lock.IsAcquired);
+ Debug.Assert(_nextFreeEntry >= 0 && _nextFreeEntry <= _entries.Length);
+ int numEntriesEncountered = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ int walk1 = _buckets[bucket];
+ int walk2 = _buckets[bucket]; // walk2 advances two elements at a time - if walk1 ever meets walk2, we've detected a cycle.
+ while (walk1 != -1)
+ {
+ numEntriesEncountered++;
+ Debug.Assert(walk1 >= 0 && walk1 < _nextFreeEntry);
+ Debug.Assert(walk2 >= -1 && walk2 < _nextFreeEntry);
+ Debug.Assert(_entries[walk1]._key != null);
+ int hashCode = _entries[walk1]._key.GetHashCode();
+ Debug.Assert(hashCode == _entries[walk1]._hashCode);
+ int storedBucket = ComputeBucket(_entries[walk1]._hashCode, _buckets.Length);
+ Debug.Assert(storedBucket == bucket);
+ walk1 = _entries[walk1]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk1 == walk2 && walk2 != -1)
+ Debug.Fail("Bucket " + bucket + " has a cycle in its linked list.");
+ }
+ }
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ Debug.Assert(numEntriesEncountered <= _nextFreeEntry);
+#endif //DEBUG
+ }
+
+ private readonly int[] _buckets;
+ private readonly Entry[] _entries;
+ private int _nextFreeEntry;
+
+ private readonly ConcurrentUnifier _owner;
+
+ private const int _initialCapacity = 5;
+ }
+
+ private struct Entry
+ {
+ public K _key;
+ public V _value;
+ public int _hashCode;
+ public int _next;
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierW.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierW.cs
new file mode 100644
index 00000000000000..1d805e0081bc13
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierW.cs
@@ -0,0 +1,396 @@
+// 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.Threading;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace System.Collections.Concurrent
+{
+ // Abstract base for a thread-safe dictionary mapping a set of keys (K) to values (V).
+ //
+ // Value immortality is guaranteed. Once entered into the dictionary, the value never expires
+ // in an observable way as long as values don't have finalizers.
+ //
+ // To create an actual dictionary, subclass this type and override the protected Factory method
+ // to instantiate values (V) for the "Add" case.
+ //
+ // The key must be of a type that implements IEquatable. The unifier calls IEquality.Equals()
+ // and Object.GetHashCode() on the keys.
+ //
+ // Deadlock risks:
+ // - Keys may be tested for equality and asked to compute their hashcode while the unifier
+ // holds its lock. Thus these operations must be written carefully to avoid deadlocks and
+ // reentrancy in to the table.
+ //
+ // - The Factory method will never be called inside the unifier lock. If two threads race to
+ // enter a value for the same key, the Factory() may get invoked twice for the same key - one
+ // of them will "win" the race and its result entered into the dictionary - other gets thrown away.
+ //
+ // Notes:
+ // - This class is used to look up types when GetType() or typeof() is invoked.
+ // That means that this class itself cannot do or call anything that does these
+ // things.
+ //
+ // - For this reason, it chooses not to mimic the official ConcurrentDictionary class
+ // (I don't even want to risk using delegates.) Even the LowLevel versions of these
+ // general utility classes may not be low-level enough for this class's purpose.
+ //
+ // Thread safety guarantees:
+ //
+ // ConcurrentUnifierW is fully thread-safe and requires no
+ // additional locking to be done by callers.
+ //
+ // Performance characteristics:
+ //
+ // ConcurrentUnifierW will not block a reader, even while
+ // the table is being written. Only one writer is allowed at a time;
+ // ConcurrentUnifierW handles the synchronization that ensures this.
+ //
+ // Safety for concurrent readers is ensured as follows:
+ //
+ // Each hash bucket is maintained as a stack. Inserts are done under
+ // a lock in one of two ways:
+ //
+ // - The entry is filled out completely, then "published" by a
+ // single write to the top of the bucket. This ensures that a reader
+ // will see a valid snapshot of the bucket, once it has read the head.
+ //
+ // - An expired WeakReference inside an existing entry is replaced atomically
+ // by a new WeakReference. A reader will either see the old expired WeakReference
+ // (if so, he'll wait for the current lock to be released then do the locked retry)
+ // or the new WeakReference (which is fine for him to see.))
+ //
+ // On resize, we allocate an entirely new table, rather than resizing
+ // in place. We fill in the new table completely, under the lock,
+ // then "publish" it with a single write. Any reader that races with
+ // this will either see the old table or the new one; each will contain
+ // the same data.
+ //
+ internal abstract class ConcurrentUnifierW
+ where K : IEquatable
+ where V : class
+ {
+ protected ConcurrentUnifierW()
+ {
+ _lock = new Lock();
+ _container = new Container(this);
+ }
+
+ //
+ // Retrieve the *unique* value for a given key. If the key was previously not entered into the dictionary,
+ // this method invokes the overridable Factory() method to create the new value. The Factory() method is
+ // invoked outside of any locks. If two threads race to enter a value for the same key, the Factory()
+ // may get invoked twice for the same key - one of them will "win" the race and its result entered into the
+ // dictionary - other gets thrown away.
+ //
+ public V GetOrAdd(K key)
+ {
+ Debug.Assert(key != null);
+ Debug.Assert(!_lock.IsAcquired, "GetOrAdd called while lock already acquired. A possible cause of this is an Equals or GetHashCode method that causes reentrancy in the table.");
+
+ int hashCode = key.GetHashCode();
+ V? value;
+ bool found = _container.TryGetValue(key, hashCode, out value);
+#if DEBUG
+ {
+ V? checkedValue;
+ bool checkedFound;
+ // In debug builds, always exercise a locked TryGet (this is a good way to detect deadlock/reentrancy through Equals/GetHashCode()).
+ using (LockHolder.Hold(_lock))
+ {
+ _container.VerifyUnifierConsistency();
+ int h = key.GetHashCode();
+ checkedFound = _container.TryGetValue(key, h, out checkedValue);
+ }
+
+ if (found)
+ {
+ // Since this DEBUG code is holding a strong reference to "value", state of a key must never go from found to not found,
+ // and only one value may exist per key.
+ Debug.Assert(checkedFound);
+ Debug.Assert(object.ReferenceEquals(checkedValue, value));
+ GC.KeepAlive(value);
+ }
+ }
+#endif //DEBUG
+ if (found)
+ return value;
+
+ value = this.Factory(key);
+
+ // This doesn't catch every object that has a finalizer, but the old saying about half a loaf...
+ Debug.Assert(!(value is IDisposable),
+ "Values placed in this table should not have finalizers. ConcurrentUnifierW guarantees observational immortality only " +
+ "in the absence of finalizers. Or to speak more plainly, we can use WeakReferences to guarantee observational immortality " +
+ "without paying the cost of storage immortality.");
+
+ if (value == null)
+ {
+ // There's no point in caching null's in the dictionary as a WeakReference of null will always show up as expired
+ // and force a re-add every time. Just return the null value without storing it. This does mean that repeated look ups
+ // for this case will be very slow - this generally corresponds to scenarios like looking for a type member that doesn't
+ // exist so hopefully, it's better to have awful throughput for such cases rather than polluting the dictionary with
+ // "null entries" that have to be special-cased for everyone.
+ return null;
+ }
+
+ using (LockHolder.Hold(_lock))
+ {
+ V? heyIWasHereFirst;
+ if (_container.TryGetValue(key, hashCode, out heyIWasHereFirst))
+ return heyIWasHereFirst;
+ if (!_container.HasCapacity)
+ _container.Resize(); // This overwrites the _container field.
+ _container.Add(key, hashCode, value);
+ return value;
+ }
+ }
+
+ protected abstract V Factory(K key);
+
+ private volatile Container _container;
+ private readonly Lock _lock;
+
+ private sealed class Container
+ {
+ public Container(ConcurrentUnifierW owner)
+ {
+ // Note: This could be done by calling Resize()'s logic but we cannot safely do that as this code path is reached
+ // during class construction time and Resize() pulls in enough stuff that we get cyclic cctor warnings from the build.
+ _buckets = new int[_initialCapacity];
+ for (int i = 0; i < _initialCapacity; i++)
+ _buckets[i] = -1;
+ _entries = new Entry[_initialCapacity];
+ _nextFreeEntry = 0;
+ _owner = owner;
+ }
+
+ private Container(ConcurrentUnifierW owner, int[] buckets, Entry[] entries, int nextFreeEntry)
+ {
+ _buckets = buckets;
+ _entries = entries;
+ _nextFreeEntry = nextFreeEntry;
+ _owner = owner;
+ }
+
+ public bool TryGetValue(K key, int hashCode, out V? value)
+ {
+ // Lock acquistion NOT required.
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+ int i = Volatile.Read(ref _buckets[bucket]);
+ while (i != -1)
+ {
+ if (key.Equals(_entries[i]._key))
+ {
+ // We found the entry for the key but the weak reference may have expired. If it did expire, do NOT
+ // try to refill it here. To maintain the appearance of value immortality, ONLY the entry belonging
+ // to the most up to date chain can be refilled in this way and we can only be sure of doing that we're
+ // inside the lock.
+ return _entries[i]._weakValue.TryGetTarget(out value);
+ }
+ i = _entries[i]._next;
+ }
+
+ value = default(V);
+ return false;
+ }
+
+ public void Add(K key, int hashCode, V value)
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+
+ // We must first determine whether we're adding because the weak reference expired or whether no entry for the key.
+ // exists at all. If the former, we must replacing the existing WeakReference as creating a duplicate entry for the key
+ // in the same Container violates the invariants of this class.
+ //
+ // Note that other threads may be doing Gets on this chain without taking locks. This is why _weakValue is marked volatile.
+ int idx = _buckets[bucket];
+ while (idx != -1)
+ {
+ if (_entries[idx]._key.Equals(key))
+ {
+#if DEBUG
+ {
+ V? heyYoureSupposedToBeDead;
+ if (_entries[idx]._weakValue.TryGetTarget(out heyYoureSupposedToBeDead))
+ Debug.Fail("Add: You were supposed to verify inside the lock that this entry's weak reference had already expired!");
+ }
+#endif //DEBUG
+ _entries[idx]._weakValue = new WeakReference(value, trackResurrection: false);
+ return;
+ }
+ idx = _entries[idx]._next;
+ }
+
+
+ // If we got here, there is no entry for this particular key. Create a new one and link it atomically
+ // to the head of the bucket chain.
+
+ int newEntryIdx = _nextFreeEntry;
+ _entries[newEntryIdx]._key = key;
+ _entries[newEntryIdx]._weakValue = new WeakReference(value, trackResurrection: false);
+ _entries[newEntryIdx]._hashCode = hashCode;
+ _entries[newEntryIdx]._next = _buckets[bucket];
+
+ _nextFreeEntry++;
+
+ // The line that atomically adds the new key/value pair. If the thread is killed before this line executes but after
+ // we've incremented _nextFreeEntry, this entry is harmlessly leaked until the next resize.
+ Volatile.Write(ref _buckets[bucket], newEntryIdx);
+
+ VerifyUnifierConsistency();
+ }
+
+ public bool HasCapacity
+ {
+ get
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+ return _nextFreeEntry != _entries.Length;
+ }
+ }
+
+ public void Resize()
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ // Before we actually grow the size of the table, figure out how much we can recover just by dropping entries with
+ // expired weak references.
+ int estimatedNumLiveEntries = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ for (int entry = _buckets[bucket]; entry != -1; entry = _entries[entry]._next)
+ {
+ // Check if the weakreference has expired.
+ V? value;
+ if (_entries[entry]._weakValue.TryGetTarget(out value))
+ estimatedNumLiveEntries++;
+ }
+ }
+ double estimatedLivePercentage = ((double)estimatedNumLiveEntries) / ((double)(_entries.Length));
+ int newSize;
+ if (estimatedLivePercentage < _growThreshold && (_entries.Length - estimatedNumLiveEntries) > _initialCapacity)
+ {
+ newSize = _buckets.Length;
+ }
+ else
+ {
+ newSize = HashHelpers.GetPrime(_buckets.Length * 2);
+#if DEBUG
+ newSize = _buckets.Length + 3;
+#endif
+ if (newSize <= _nextFreeEntry)
+ throw new OutOfMemoryException();
+ }
+ Entry[] newEntries = new Entry[newSize];
+ int[] newBuckets = new int[newSize];
+ for (int i = 0; i < newSize; i++)
+ newBuckets[i] = -1;
+
+ // Note that we walk the bucket chains rather than iterating over _entries. This is because we allow for the possibility
+ // of abandoned entries (with undefined contents) if a thread is killed between allocating an entry and linking it onto the
+ // bucket chain.
+ int newNextFreeEntry = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ for (int entry = _buckets[bucket]; entry != -1; entry = _entries[entry]._next)
+ {
+ // Check if the weakreference has expired. If so, this is where we drop the entry altogether.
+ V? value;
+ if (_entries[entry]._weakValue.TryGetTarget(out value))
+ {
+ newEntries[newNextFreeEntry]._key = _entries[entry]._key;
+ newEntries[newNextFreeEntry]._weakValue = _entries[entry]._weakValue;
+ newEntries[newNextFreeEntry]._hashCode = _entries[entry]._hashCode;
+ int newBucket = ComputeBucket(newEntries[newNextFreeEntry]._hashCode, newSize);
+ newEntries[newNextFreeEntry]._next = newBuckets[newBucket];
+ newBuckets[newBucket] = newNextFreeEntry;
+ newNextFreeEntry++;
+ }
+ }
+ }
+
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ // In addition, we don't bother copying entries where the weak reference has expired.
+ Debug.Assert(newNextFreeEntry <= _nextFreeEntry);
+
+ // The line that atomically installs the resize. If this thread is killed before this point,
+ // the table remains full and the next guy attempting an add will have to redo the resize.
+ _owner._container = new Container(_owner, newBuckets, newEntries, newNextFreeEntry);
+
+ _owner._container.VerifyUnifierConsistency();
+ }
+
+ private static int ComputeBucket(int hashCode, int numBuckets)
+ {
+ int bucket = (hashCode & 0x7fffffff) % numBuckets;
+ return bucket;
+ }
+
+ [Conditional("DEBUG")]
+ public void VerifyUnifierConsistency()
+ {
+#if DEBUG
+ // There's a point at which this check becomes gluttonous, even by checked build standards...
+ if (_nextFreeEntry >= 5000 || (0 != (_nextFreeEntry % 100)))
+ return;
+
+ Debug.Assert(_owner._lock.IsAcquired);
+ Debug.Assert(_nextFreeEntry >= 0 && _nextFreeEntry <= _entries.Length);
+ int numEntriesEncountered = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ int walk1 = _buckets[bucket];
+ int walk2 = _buckets[bucket]; // walk2 advances two elements at a time - if walk1 ever meets walk2, we've detected a cycle.
+ while (walk1 != -1)
+ {
+ numEntriesEncountered++;
+ Debug.Assert(walk1 >= 0 && walk1 < _nextFreeEntry);
+ Debug.Assert(walk2 >= -1 && walk2 < _nextFreeEntry);
+ Debug.Assert(_entries[walk1]._key != null);
+ int hashCode = _entries[walk1]._key.GetHashCode();
+ Debug.Assert(hashCode == _entries[walk1]._hashCode);
+ Debug.Assert(_entries[walk1]._weakValue != null);
+ int storedBucket = ComputeBucket(_entries[walk1]._hashCode, _buckets.Length);
+ Debug.Assert(storedBucket == bucket);
+ walk1 = _entries[walk1]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk1 == walk2 && walk2 != -1)
+ Debug.Fail("Bucket " + bucket + " has a cycle in its linked list.");
+ }
+ }
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ Debug.Assert(numEntriesEncountered <= _nextFreeEntry);
+#endif //DEBUG
+ }
+
+ private readonly int[] _buckets;
+ private readonly Entry[] _entries;
+ private int _nextFreeEntry;
+
+ private readonly ConcurrentUnifierW _owner;
+
+ private const int _initialCapacity = 5;
+ private const double _growThreshold = 0.75;
+ }
+
+ private struct Entry
+ {
+ public K _key;
+ public volatile WeakReference _weakValue;
+ public int _hashCode;
+ public int _next;
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierWKeyed.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierWKeyed.cs
new file mode 100644
index 00000000000000..c85567e76c4075
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/ConcurrentUnifierWKeyed.cs
@@ -0,0 +1,390 @@
+// 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.Threading;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace System.Collections.Concurrent
+{
+ // Abstract base for a thread-safe dictionary mapping a set of keys (K) to values (V).
+ //
+ // This flavor of ConcurrentUnifier holds values using weak references. It does not store the keys directly. Instead, values are
+ // required to contain the key and expose it via IKeyedItem. This flavor should be used in situations where the keys themselves
+ // could store direct or indirect references to the value (thus, preventing the value's from being GC'd if the table were to
+ // store the keys directly.)
+ //
+ // Value immortality is guaranteed. Once entered into the dictionary, the value never expires
+ // in an observable way as long as values don't have finalizers.
+ //
+ // To create an actual dictionary, subclass this type and override the protected Factory method
+ // to instantiate values (V) for the "Add" case.
+ //
+ // The key must be of a type that implements IEquatable. The unifier calls IEquality.Equals()
+ // and Object.GetHashCode() on the keys.
+ //
+ // The value must be a reference type that implements IKeyedItem. The unifier invokes the
+ // IKeyedItem.PrepareKey() method (outside the lock) on any value returned by the factory. This gives the value
+ // a chance to do any lazy evaluation of the keys while it's safe to do so.
+ //
+ // Deadlock risks:
+ // - Keys may be tested for equality and asked to compute their hashcode while the unifier
+ // holds its lock. Thus these operations must be written carefully to avoid deadlocks and
+ // reentrancy in to the table.
+ //
+ // - Values may get their IKeyedItem.Key property called while the unifier holds its lock.
+ // Values that need to do lazy evaluation to compute their keys should do that in the PrepareKey()
+ // method which the unifier promises to call outside the lock prior to entering the value into the table.
+ //
+ // - The Factory method will never be called inside the unifier lock. If two threads race to
+ // enter a value for the same key, the Factory() may get invoked twice for the same key - one
+ // of them will "win" the race and its result entered into the dictionary - other gets thrown away.
+ //
+ // Notes:
+ // - This class is used to look up types when GetType() or typeof() is invoked.
+ // That means that this class itself cannot do or call anything that does these
+ // things.
+ //
+ // - For this reason, it chooses not to mimic the official ConcurrentDictionary class
+ // (I don't even want to risk using delegates.) Even the LowLevel versions of these
+ // general utility classes may not be low-level enough for this class's purpose.
+ //
+ // Thread safety guarantees:
+ //
+ // ConcurrentUnifier is fully thread-safe and requires no
+ // additional locking to be done by callers.
+ //
+ // Performance characteristics:
+ //
+ // ConcurrentUnifier will not block a reader, even while
+ // the table is being written. Only one writer is allowed at a time;
+ // ConcurrentUnifier handles the synchronization that ensures this.
+ //
+ // Safety for concurrent readers is ensured as follows:
+ //
+ // Each hash bucket is maintained as a stack. Inserts are done under
+ // a lock in one of two ways:
+ //
+ // - The entry is filled out completely, then "published" by a
+ // single write to the top of the bucket. This ensures that a reader
+ // will see a valid snapshot of the bucket, once it has read the head.
+ //
+ // - An expired WeakReference inside an existing entry is replaced atomically
+ // by a new WeakReference. A reader will either see the old expired WeakReference
+ // (if so, he'll wait for the current lock to be released then do the locked retry)
+ // or the new WeakReference (which is fine for him to see.))
+ //
+ // On resize, we allocate an entirely new table, rather than resizing
+ // in place. We fill in the new table completely, under the lock,
+ // then "publish" it with a single write. Any reader that races with
+ // this will either see the old table or the new one; each will contain
+ // the same data.
+ //
+ internal abstract class ConcurrentUnifierWKeyed
+ where K : IEquatable
+ where V : class, IKeyedItem
+ {
+ protected ConcurrentUnifierWKeyed()
+ {
+ _lock = new Lock();
+ _container = new Container(this);
+ }
+
+ //
+ // Retrieve the *unique* value for a given key. If the key was previously not entered into the dictionary,
+ // this method invokes the overridable Factory() method to create the new value. The Factory() method is
+ // invoked outside of any locks. If two threads race to enter a value for the same key, the Factory()
+ // may get invoked twice for the same key - one of them will "win" the race and its result entered into the
+ // dictionary - other gets thrown away.
+ //
+ public V GetOrAdd(K key)
+ {
+ Debug.Assert(key != null);
+ Debug.Assert(!_lock.IsAcquired, "GetOrAdd called while lock already acquired. A possible cause of this is an Equals or GetHashCode method that causes reentrancy in the table.");
+
+ int hashCode = key.GetHashCode();
+ V value;
+ bool found = _container.TryGetValue(key, hashCode, out value);
+#if DEBUG
+ {
+ V checkedValue;
+ bool checkedFound;
+ // In debug builds, always exercise a locked TryGet (this is a good way to detect deadlock/reentrancy through Equals/GetHashCode()).
+ using (LockHolder.Hold(_lock))
+ {
+ _container.VerifyUnifierConsistency();
+ int h = key.GetHashCode();
+ checkedFound = _container.TryGetValue(key, h, out checkedValue);
+ }
+
+ if (found)
+ {
+ // Since this DEBUG code is holding a strong reference to "value", state of a key must never go from found to not found,
+ // and only one value may exist per key.
+ Debug.Assert(checkedFound);
+ Debug.Assert(object.ReferenceEquals(checkedValue, value));
+ GC.KeepAlive(value);
+ }
+ }
+#endif //DEBUG
+ if (found)
+ return value;
+
+ value = this.Factory(key);
+
+ // This doesn't catch every object that has a finalizer, but the old saying about half a loaf...
+ Debug.Assert(!(value is IDisposable),
+ "Values placed in this table should not have finalizers. ConcurrentUnifiers guarantee observational immortality only " +
+ "in the absence of finalizers. Or to speak more plainly, we can use WeakReferences to guarantee observational immortality " +
+ "without paying the cost of storage immortality.");
+
+ if (value == null)
+ {
+ // There's no point in caching null's in the dictionary as a WeakReference of null will always show up as expired
+ // and force a re-add every time. Just return the null value without storing it. This does mean that repeated look ups
+ // for this case will be very slow - this generally corresponds to scenarios like looking for a type member that doesn't
+ // exist so hopefully, it's better to have awful throughput for such cases rather than polluting the dictionary with
+ // "null entries" that have to be special-cased for everyone.
+ return null;
+ }
+
+ // While still outside the lock, invoke the value's PrepareKey method to give the chance to do any lazy evaluation
+ // it needs to produce the key quickly and in a deadlock-free manner once we're inside the lock.
+ value.PrepareKey();
+
+ using (LockHolder.Hold(_lock))
+ {
+ V heyIWasHereFirst;
+ if (_container.TryGetValue(key, hashCode, out heyIWasHereFirst))
+ return heyIWasHereFirst;
+ if (!_container.HasCapacity)
+ _container.Resize(); // This overwrites the _container field.
+ _container.Add(key, hashCode, value);
+ return value;
+ }
+ }
+
+ protected abstract V Factory(K key);
+
+ private volatile Container _container;
+ private readonly Lock _lock;
+
+ private sealed class Container
+ {
+ public Container(ConcurrentUnifierWKeyed owner)
+ {
+ // Note: This could be done by calling Resize()'s logic but we cannot safely do that as this code path is reached
+ // during class construction time and Resize() pulls in enough stuff that we get cyclic cctor warnings from the build.
+ _buckets = new int[_initialCapacity];
+ for (int i = 0; i < _initialCapacity; i++)
+ _buckets[i] = -1;
+ _entries = new Entry[_initialCapacity];
+ _nextFreeEntry = 0;
+ _owner = owner;
+ }
+
+ private Container(ConcurrentUnifierWKeyed owner, int[] buckets, Entry[] entries, int nextFreeEntry)
+ {
+ _buckets = buckets;
+ _entries = entries;
+ _nextFreeEntry = nextFreeEntry;
+ _owner = owner;
+ }
+
+ public bool TryGetValue(K key, int hashCode, out V value)
+ {
+ // Lock acquistion NOT required.
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+ int i = Volatile.Read(ref _buckets[bucket]);
+ while (i != -1)
+ {
+ V? actualValue;
+ if (hashCode == _entries[i]._hashCode && _entries[i]._weakValue.TryGetTarget(out actualValue))
+ {
+ K actualKey = actualValue.Key;
+ if (key.Equals(actualKey))
+ {
+ value = actualValue;
+ return true;
+ }
+ }
+ i = _entries[i]._next;
+ }
+
+ value = default(V);
+ return false;
+ }
+
+ public void Add(K key, int hashCode, V value)
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ int bucket = ComputeBucket(hashCode, _buckets.Length);
+ int newEntryIdx = _nextFreeEntry;
+ _entries[newEntryIdx]._weakValue = new WeakReference(value, trackResurrection: false);
+ _entries[newEntryIdx]._hashCode = hashCode;
+ _entries[newEntryIdx]._next = _buckets[bucket];
+
+ _nextFreeEntry++;
+
+ // The line that atomically adds the new key/value pair. If the thread is killed before this line executes but after
+ // we've incremented _nextFreeEntry, this entry is harmlessly leaked until the next resize.
+ Volatile.Write(ref _buckets[bucket], newEntryIdx);
+
+ VerifyUnifierConsistency();
+ }
+
+ public bool HasCapacity
+ {
+ get
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+ return _nextFreeEntry != _entries.Length;
+ }
+ }
+
+ public void Resize()
+ {
+ Debug.Assert(_owner._lock.IsAcquired);
+
+ // Before we actually grow the size of the table, figure out how much we can recover just by dropping entries with
+ // expired weak references.
+ int estimatedNumLiveEntries = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ for (int entry = _buckets[bucket]; entry != -1; entry = _entries[entry]._next)
+ {
+ // Check if the weakreference has expired.
+ V? value;
+ if (_entries[entry]._weakValue.TryGetTarget(out value))
+ estimatedNumLiveEntries++;
+ }
+ }
+ double estimatedLivePercentage = ((double)estimatedNumLiveEntries) / ((double)(_entries.Length));
+ int newSize;
+ if (estimatedLivePercentage < _growThreshold && (_entries.Length - estimatedNumLiveEntries) > _initialCapacity)
+ {
+ newSize = _buckets.Length;
+ }
+ else
+ {
+ newSize = HashHelpers.GetPrime(_buckets.Length * 2);
+#if DEBUG
+ newSize = _buckets.Length + 3;
+#endif
+ if (newSize <= _nextFreeEntry)
+ throw new OutOfMemoryException();
+ }
+ Entry[] newEntries = new Entry[newSize];
+ int[] newBuckets = new int[newSize];
+ for (int i = 0; i < newSize; i++)
+ newBuckets[i] = -1;
+
+ // Note that we walk the bucket chains rather than iterating over _entries. This is because we allow for the possibility
+ // of abandoned entries (with undefined contents) if a thread is killed between allocating an entry and linking it onto the
+ // bucket chain.
+ int newNextFreeEntry = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ for (int entry = _buckets[bucket]; entry != -1; entry = _entries[entry]._next)
+ {
+ // Check if the weakreference has expired. If so, this is where we drop the entry altogether.
+ V? value;
+ if (_entries[entry]._weakValue.TryGetTarget(out value))
+ {
+ newEntries[newNextFreeEntry]._weakValue = _entries[entry]._weakValue;
+ newEntries[newNextFreeEntry]._hashCode = _entries[entry]._hashCode;
+ int newBucket = ComputeBucket(newEntries[newNextFreeEntry]._hashCode, newSize);
+ newEntries[newNextFreeEntry]._next = newBuckets[newBucket];
+ newBuckets[newBucket] = newNextFreeEntry;
+ newNextFreeEntry++;
+ }
+ }
+ }
+
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ // In addition, we don't bother copying entries where the weak reference has expired.
+ Debug.Assert(newNextFreeEntry <= _nextFreeEntry);
+
+ // The line that atomically installs the resize. If this thread is killed before this point,
+ // the table remains full and the next guy attempting an add will have to redo the resize.
+ _owner._container = new Container(_owner, newBuckets, newEntries, newNextFreeEntry);
+
+ _owner._container.VerifyUnifierConsistency();
+ }
+
+ private static int ComputeBucket(int hashCode, int numBuckets)
+ {
+ int bucket = (hashCode & 0x7fffffff) % numBuckets;
+ return bucket;
+ }
+
+ [Conditional("DEBUG")]
+ public void VerifyUnifierConsistency()
+ {
+#if DEBUG
+ // There's a point at which this check becomes gluttonous, even by checked build standards...
+ if (_nextFreeEntry >= 5000 && (0 != (_nextFreeEntry % 100)))
+ return;
+
+ Debug.Assert(_owner._lock.IsAcquired);
+ Debug.Assert(_nextFreeEntry >= 0 && _nextFreeEntry <= _entries.Length);
+ int numEntriesEncountered = 0;
+ for (int bucket = 0; bucket < _buckets.Length; bucket++)
+ {
+ int walk1 = _buckets[bucket];
+ int walk2 = _buckets[bucket]; // walk2 advances two elements at a time - if walk1 ever meets walk2, we've detected a cycle.
+ while (walk1 != -1)
+ {
+ numEntriesEncountered++;
+ Debug.Assert(walk1 >= 0 && walk1 < _nextFreeEntry);
+ Debug.Assert(walk2 >= -1 && walk2 < _nextFreeEntry);
+ Debug.Assert(_entries[walk1]._weakValue != null);
+ V? value;
+ if (_entries[walk1]._weakValue.TryGetTarget(out value))
+ {
+ K key = value.Key;
+ Debug.Assert(key != null);
+ int hashCode = key.GetHashCode();
+ Debug.Assert(hashCode == _entries[walk1]._hashCode);
+ }
+
+ int storedBucket = ComputeBucket(_entries[walk1]._hashCode, _buckets.Length);
+ Debug.Assert(storedBucket == bucket);
+ walk1 = _entries[walk1]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk2 != -1)
+ walk2 = _entries[walk2]._next;
+ if (walk1 == walk2 && walk2 != -1)
+ Debug.Fail("Bucket " + bucket + " has a cycle in its linked list.");
+ }
+ }
+ // The assertion is "<=" rather than "==" because we allow an entry to "leak" until the next resize if
+ // a thread died between the time between we allocated the entry and the time we link it into the bucket stack.
+ Debug.Assert(numEntriesEncountered <= _nextFreeEntry);
+#endif //DEBUG
+ }
+
+ private readonly int[] _buckets;
+ private readonly Entry[] _entries;
+ private int _nextFreeEntry;
+
+ private readonly ConcurrentUnifierWKeyed _owner;
+
+ private const int _initialCapacity = 5;
+ private const double _growThreshold = 0.75;
+ }
+
+ private struct Entry
+ {
+ public WeakReference _weakValue;
+ public int _hashCode;
+ public int _next;
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/IKeyedItem.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/IKeyedItem.cs
new file mode 100644
index 00000000000000..ea43941b6f2ec5
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Concurrent/IKeyedItem.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace System.Collections.Concurrent
+{
+ //
+ // Objects that want to be used as values in a keyed ConcurrentUnifier need to implement this interface.
+ // Keyed items are values that contain their own keys and can produce them on demand.
+ //
+ internal interface IKeyedItem where K : IEquatable
+ {
+ //
+ // This method is the keyed item's chance to do any lazy evaluation needed to produce the key quickly.
+ // Concurrent unifiers are guaranteed to invoke this method at least once and wait for it
+ // to complete before invoking the Key property. The unifier lock is NOT held across the call.
+ //
+ // PrepareKey() must be idempodent and thread-safe. It may be invoked multiple times and concurrently.
+ //
+ void PrepareKey();
+
+ //
+ // Produce the key. This is a high-traffic property and is called while the hash table's lock is held. Thus, it should
+ // return a precomputed stored value and refrain from invoking other methods. If the keyed item wishes to
+ // do lazy evaluation of the key, it should do so in the PrepareKey() method.
+ //
+ K Key { get; }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/Empty.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/Empty.cs
new file mode 100644
index 00000000000000..bef0bfde53d334
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/Empty.cs
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace System.Collections.Generic
+{
+ //
+ // Helper class to store reusable empty IEnumerables.
+ //
+ internal static class Empty
+ {
+ //
+ // Returns a reusable empty IEnumerable (that does not secretly implement more advanced collection interfaces.)
+ //
+ public static IEnumerable Enumerable
+ {
+ get
+ {
+ return _enumerable;
+ }
+ }
+
+ private sealed class EmptyEnumImpl : IEnumerable, IEnumerator
+ {
+ public IEnumerator GetEnumerator()
+ {
+ return this;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this;
+ }
+
+ public T Current
+ {
+ get { throw new InvalidOperationException(); }
+ }
+
+ object IEnumerator.Current
+ {
+ get { throw new InvalidOperationException(); }
+ }
+
+ public bool MoveNext()
+ {
+ return false;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+
+ private static IEnumerable _enumerable = new EmptyEnumImpl();
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/EnumerableExtensions.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/EnumerableExtensions.cs
new file mode 100644
index 00000000000000..9e8fb9790b3b6d
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/EnumerableExtensions.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace System.Collections.Generic
+{
+ internal static class EnumerableExtensions
+ {
+ // Used to prevent returning values out of IEnumerable<>-typed properties
+ // that an untrusted caller could cast back to array or List.
+ public static IEnumerable AsNothingButIEnumerable(this IEnumerable en)
+ {
+ foreach (T t in en)
+ yield return t;
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs
new file mode 100644
index 00000000000000..cd98bef0d7d8bc
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelDictionary.cs
@@ -0,0 +1,316 @@
+// 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;
+using System.Collections.Generic;
+
+namespace System.Collections.Generic
+{
+ /*============================================================
+ **
+ ** Class: LowLevelDictionary
+ **
+ ** Private version of Dictionary<> for internal System.Private.CoreLib use. This
+ ** permits sharing more source between BCL and System.Private.CoreLib (as well as the
+ ** fact that Dictionary<> is just a useful class in general.)
+ **
+ ** This does not strive to implement the full api surface area
+ ** (but any portion it does implement should match the real Dictionary<>'s
+ ** behavior.)
+ **
+ ===========================================================*/
+#if TYPE_LOADER_IMPLEMENTATION
+ [System.Runtime.CompilerServices.ForceDictionaryLookups]
+#endif
+ internal class LowLevelDictionary where TKey : IEquatable
+ {
+ private const int DefaultSize = 17;
+
+ public LowLevelDictionary()
+ : this(DefaultSize)
+ {
+ }
+
+ public LowLevelDictionary(int capacity)
+ {
+ Clear(capacity);
+ }
+
+ public int Count
+ {
+ get
+ {
+ return _numEntries;
+ }
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+
+ Entry entry = Find(key);
+ if (entry == null)
+ throw new KeyNotFoundException();
+ return entry.m_value;
+ }
+ set
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+
+ _version++;
+ Entry entry = Find(key);
+ if (entry != null)
+ entry.m_value = value;
+ else
+ UncheckedAdd(key, value);
+ }
+ }
+
+ public bool TryGetValue(TKey key, out TValue? value)
+ {
+ value = default(TValue);
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+ Entry entry = Find(key);
+ if (entry != null)
+ {
+ value = entry.m_value;
+ return true;
+ }
+ return false;
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+ Entry entry = Find(key);
+ if (entry != null)
+ throw new ArgumentException(SR.Format(SR.Argument_AddingDuplicate, key));
+ _version++;
+ UncheckedAdd(key, value);
+ }
+
+ public void Clear(int capacity = DefaultSize)
+ {
+ _version++;
+ _buckets = new Entry[capacity];
+ _numEntries = 0;
+ }
+
+ public bool Remove(TKey key)
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+ int bucket = GetBucket(key);
+ Entry? prev = null;
+ Entry? entry = _buckets[bucket];
+ while (entry != null)
+ {
+ if (key.Equals(entry.m_key))
+ {
+ if (prev == null)
+ {
+ _buckets[bucket] = entry.m_next;
+ }
+ else
+ {
+ prev.m_next = entry.m_next;
+ }
+ _version++;
+ _numEntries--;
+ return true;
+ }
+
+ prev = entry;
+ entry = entry.m_next;
+ }
+ return false;
+ }
+
+ internal TValue LookupOrAdd(TKey key, TValue value)
+ {
+ Entry entry = Find(key);
+ if (entry != null)
+ return entry.m_value;
+ UncheckedAdd(key, value);
+ return value;
+ }
+
+ private Entry Find(TKey key)
+ {
+ int bucket = GetBucket(key);
+ Entry? entry = _buckets[bucket];
+ while (entry != null)
+ {
+ if (key.Equals(entry.m_key))
+ return entry;
+
+ entry = entry.m_next;
+ }
+ return null;
+ }
+
+ private Entry UncheckedAdd(TKey key, TValue value)
+ {
+ Entry entry = new Entry();
+ entry.m_key = key;
+ entry.m_value = value;
+
+ int bucket = GetBucket(key);
+ entry.m_next = _buckets[bucket];
+ _buckets[bucket] = entry;
+
+ _numEntries++;
+ if (_numEntries > (_buckets.Length * 2))
+ ExpandBuckets();
+
+ return entry;
+ }
+
+
+ private void ExpandBuckets()
+ {
+ try
+ {
+ int newNumBuckets = _buckets.Length * 2 + 1;
+ Entry[] newBuckets = new Entry[newNumBuckets];
+ for (int i = 0; i < _buckets.Length; i++)
+ {
+ Entry? entry = _buckets[i];
+ while (entry != null)
+ {
+ Entry? nextEntry = entry.m_next;
+
+ int bucket = GetBucket(entry.m_key, newNumBuckets);
+ entry.m_next = newBuckets[bucket];
+ newBuckets[bucket] = entry;
+
+ entry = nextEntry;
+ }
+ }
+ _buckets = newBuckets;
+ }
+ catch (OutOfMemoryException)
+ {
+ }
+ }
+
+ private int GetBucket(TKey key, int numBuckets = 0)
+ {
+ int h = key.GetHashCode();
+ h &= 0x7fffffff;
+ return (h % (numBuckets == 0 ? _buckets.Length : numBuckets));
+ }
+
+
+#if TYPE_LOADER_IMPLEMENTATION
+ [System.Runtime.CompilerServices.ForceDictionaryLookups]
+#endif
+ private sealed class Entry
+ {
+ public TKey m_key;
+ public TValue m_value;
+ public Entry? m_next;
+ }
+
+ private Entry?[] _buckets;
+ private int _numEntries;
+ private int _version;
+
+#if TYPE_LOADER_IMPLEMENTATION
+ [System.Runtime.CompilerServices.ForceDictionaryLookups]
+#endif
+ protected sealed class LowLevelDictEnumerator : IEnumerator>
+ {
+ public LowLevelDictEnumerator(LowLevelDictionary dict)
+ {
+ _dict = dict;
+ _version = _dict._version;
+ Entry[] entries = new Entry[_dict._numEntries];
+ int dst = 0;
+ for (int bucket = 0; bucket < _dict._buckets.Length; bucket++)
+ {
+ Entry? entry = _dict._buckets[bucket];
+ while (entry != null)
+ {
+ entries[dst++] = entry;
+ entry = entry.m_next;
+ }
+ }
+ _entries = entries;
+ Reset();
+ }
+
+ public KeyValuePair Current
+ {
+ get
+ {
+ if (_version != _dict._version)
+ throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
+ if (_curPosition == -1 || _curPosition == _entries.Length)
+ throw new InvalidOperationException("InvalidOperation_EnumOpCantHappen");
+ Entry entry = _entries[_curPosition];
+ return new KeyValuePair(entry.m_key, entry.m_value);
+ }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ if (_version != _dict._version)
+ throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
+ if (_curPosition != _entries.Length)
+ _curPosition++;
+ bool anyMore = (_curPosition != _entries.Length);
+ return anyMore;
+ }
+
+ object IEnumerator.Current
+ {
+ get
+ {
+ KeyValuePair kv = Current;
+ return kv;
+ }
+ }
+
+ public void Reset()
+ {
+ if (_version != _dict._version)
+ throw new InvalidOperationException("InvalidOperation_EnumFailedVersion");
+ _curPosition = -1;
+ }
+
+ private LowLevelDictionary _dict;
+ private Entry[] _entries;
+ private int _curPosition;
+ private int _version;
+ }
+ }
+
+ ///
+ /// LowLevelDictionary when enumeration is needed
+ ///
+ internal sealed class LowLevelDictionaryWithIEnumerable : LowLevelDictionary, IEnumerable> where TKey : IEquatable
+ {
+ public IEnumerator> GetEnumerator()
+ {
+ return new LowLevelDictEnumerator(this);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ IEnumerator> ie = GetEnumerator();
+ return ie;
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs
new file mode 100644
index 00000000000000..9909556b183305
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Collections/Generic/LowLevelList.cs
@@ -0,0 +1,577 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*============================================================
+**
+**
+** Private version of List for internal System.Private.CoreLib use. This
+** permits sharing more source between BCL and System.Private.CoreLib (as well as the
+** fact that List is just a useful class in general.)
+**
+** This does not strive to implement the full api surface area
+** (but any portion it does implement should match the real List's
+** behavior.)
+**
+** This file is a subset of System.Collections\System\Collections\Generics\List.cs
+** and should be kept in sync with that file.
+**
+===========================================================*/
+
+using System;
+using System.Diagnostics;
+
+namespace System.Collections.Generic
+{
+ // Implements a variable-size List that uses an array of objects to store the
+ // elements. A List has a capacity, which is the allocated length
+ // of the internal array. As elements are added to a List, the capacity
+ // of the List is automatically increased as required by reallocating the
+ // internal array.
+ //
+ // LowLevelList with no interface implementation minimizes both code and data size.
+ // Data size is smaller because there will be minimal virtual function table.
+ // Code size is smaller because only functions called will be in the binary.
+ // Use LowLevelListWithIList for IList support
+ [DebuggerDisplay("Count = {Count}")]
+#if TYPE_LOADER_IMPLEMENTATION
+ [System.Runtime.CompilerServices.ForceDictionaryLookups]
+#endif
+ internal class LowLevelList
+ {
+ private const int _defaultCapacity = 4;
+
+ protected T?[] _items;
+ protected int _size;
+ protected int _version;
+
+#pragma warning disable CA1825 // avoid the extra generic instantiation for Array.Empty()
+ private static readonly T[] s_emptyArray = new T[0];
+#pragma warning restore CA1825
+
+ // Constructs a List. The list is initially empty and has a capacity
+ // of zero. Upon adding the first element to the list the capacity is
+ // increased to 4, and then increased in multiples of two as required.
+ public LowLevelList()
+ {
+ _items = s_emptyArray;
+ }
+
+ // Constructs a List with a given initial capacity. The list is
+ // initially empty, but will have room for the given number of elements
+ // before any reallocations are required.
+ //
+ public LowLevelList(int capacity)
+ {
+ if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity));
+
+ if (capacity == 0)
+ _items = s_emptyArray;
+ else
+ _items = new T[capacity];
+ }
+
+ // Constructs a List, copying the contents of the given collection. The
+ // size and capacity of the new list will both be equal to the size of the
+ // given collection.
+ //
+ public LowLevelList(IEnumerable collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection));
+
+ ICollection? c = collection as ICollection;
+ if (c != null)
+ {
+ int count = c.Count;
+ if (count == 0)
+ {
+ _items = s_emptyArray;
+ }
+ else
+ {
+ _items = new T[count];
+ c.CopyTo(_items, 0);
+ _size = count;
+ }
+ }
+ else
+ {
+ _size = 0;
+ _items = s_emptyArray;
+ // This enumerable could be empty. Let Add allocate a new array, if needed.
+ // Note it will also go to _defaultCapacity first, not 1, then 2, etc.
+
+ using (IEnumerator en = collection.GetEnumerator())
+ {
+ while (en.MoveNext())
+ {
+ Add(en.Current);
+ }
+ }
+ }
+ }
+
+ // Gets and sets the capacity of this list. The capacity is the size of
+ // the internal array used to hold items. When set, the internal
+ // array of the list is reallocated to the given capacity.
+ //
+ public int Capacity
+ {
+ get
+ {
+ return _items.Length;
+ }
+ set
+ {
+ if (value < _size)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ if (value != _items.Length)
+ {
+ if (value > 0)
+ {
+ T[] newItems = new T[value];
+ Array.Copy(_items, 0, newItems, 0, _size);
+ _items = newItems;
+ }
+ else
+ {
+ _items = s_emptyArray;
+ }
+ }
+ }
+ }
+
+ // Read-only property describing how many elements are in the List.
+ public int Count
+ {
+ get
+ {
+ return _size;
+ }
+ }
+
+ // Sets or Gets the element at the given index.
+ //
+ public T this[int index]
+ {
+ get
+ {
+ // Following trick can reduce the range check by one
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ return _items[index];
+ }
+
+ set
+ {
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+ _items[index] = value;
+ _version++;
+ }
+ }
+
+
+ // Adds the given object to the end of this list. The size of the list is
+ // increased by one. If required, the capacity of the list is doubled
+ // before adding the new element.
+ //
+ public void Add(T item)
+ {
+ if (_size == _items.Length) EnsureCapacity(_size + 1);
+ _items[_size++] = item;
+ _version++;
+ }
+
+ // Ensures that the capacity of this list is at least the given minimum
+ // value. If the currect capacity of the list is less than min, the
+ // capacity is increased to twice the current capacity or to min,
+ // whichever is larger.
+ private void EnsureCapacity(int min)
+ {
+ if (_items.Length < min)
+ {
+ int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;
+ // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
+ // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
+ //if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength;
+ if (newCapacity < min) newCapacity = min;
+ Capacity = newCapacity;
+ }
+ }
+
+#if !TYPE_LOADER_IMPLEMENTATION
+ // Adds the elements of the given collection to the end of this list. If
+ // required, the capacity of the list is increased to twice the previous
+ // capacity or the new size, whichever is larger.
+ //
+ public void AddRange(IEnumerable collection)
+ {
+
+ InsertRange(_size, collection);
+ }
+
+ // Clears the contents of List.
+ public void Clear()
+ {
+ if (_size > 0)
+ {
+ Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
+ _size = 0;
+ }
+ _version++;
+ }
+
+ // Contains returns true if the specified element is in the List.
+ // It does a linear, O(n) search. Equality is determined by calling
+ // item.Equals().
+ //
+ public bool Contains(T item)
+ {
+ if ((object?)item == null)
+ {
+ for (int i = 0; i < _size; i++)
+ if ((object?)_items[i] == null)
+ return true;
+ return false;
+ }
+ else
+ {
+ int index = IndexOf(item);
+ if (index >= 0)
+ return true;
+ return false;
+ }
+ }
+
+
+ // Copies a section of this list to the given array at the given index.
+ //
+ // The method uses the Array.Copy method to copy the elements.
+ //
+ public void CopyTo(int index, T[] array, int arrayIndex, int count)
+ {
+ if (_size - index < count)
+ {
+ throw new ArgumentException();
+ }
+
+ // Delegate rest of error checking to Array.Copy.
+ Array.Copy(_items, index, array, arrayIndex, count);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ // Delegate rest of error checking to Array.Copy.
+ Array.Copy(_items, 0, array, arrayIndex, _size);
+ }
+
+ // Returns the index of the first occurrence of a given value in a range of
+ // this list. The list is searched forwards from beginning to end.
+ // The elements of the list are compared to the given value using the
+ // Object.Equals method.
+ //
+ // This method uses the Array.IndexOf method to perform the
+ // search.
+ //
+ public int IndexOf(T item)
+ {
+ return Array.IndexOf(_items, item, 0, _size);
+ }
+
+
+ // Returns the index of the first occurrence of a given value in a range of
+ // this list. The list is searched forwards, starting at index
+ // index and ending at count number of elements. The
+ // elements of the list are compared to the given value using the
+ // Object.Equals method.
+ //
+ // This method uses the Array.IndexOf method to perform the
+ // search.
+ //
+ public int IndexOf(T item, int index)
+ {
+ if (index > _size)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ return Array.IndexOf(_items, item, index, _size - index);
+ }
+
+ // Inserts an element into this list at a given index. The size of the list
+ // is increased by one. If required, the capacity of the list is doubled
+ // before inserting the new element.
+ //
+ public void Insert(int index, T item)
+ {
+ // Note that insertions at the end are legal.
+ if ((uint)index > (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+ if (_size == _items.Length) EnsureCapacity(_size + 1);
+ if (index < _size)
+ {
+ Array.Copy(_items, index, _items, index + 1, _size - index);
+ }
+ _items[index] = item;
+ _size++;
+ _version++;
+ }
+
+ // Inserts the elements of the given collection at a given index. If
+ // required, the capacity of the list is increased to twice the previous
+ // capacity or the new size, whichever is larger. Ranges may be added
+ // to the end of the list by setting index to the List's size.
+ //
+ public void InsertRange(int index, IEnumerable collection)
+ {
+ if (collection == null)
+ {
+ throw new ArgumentNullException(nameof(collection));
+ }
+
+ if ((uint)index > (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+
+ ICollection? c = collection as ICollection;
+ if (c != null)
+ { // if collection is ICollection
+ int count = c.Count;
+ if (count > 0)
+ {
+ EnsureCapacity(_size + count);
+ if (index < _size)
+ {
+ Array.Copy(_items, index, _items, index + count, _size - index);
+ }
+
+ // If we're inserting a List into itself, we want to be able to deal with that.
+ if (this == c)
+ {
+ // Copy first part of _items to insert location
+ Array.Copy(_items, 0, _items, index, index);
+ // Copy last part of _items back to inserted location
+ Array.Copy(_items, index + count, _items, index * 2, _size - index);
+ }
+ else
+ {
+ T[] itemsToInsert = new T[count];
+ c.CopyTo(itemsToInsert, 0);
+ Array.Copy(itemsToInsert, 0, _items, index, count);
+ }
+ _size += count;
+ }
+ }
+ else
+ {
+ using (IEnumerator en = collection.GetEnumerator())
+ {
+ while (en.MoveNext())
+ {
+ Insert(index++, en.Current);
+ }
+ }
+ }
+ _version++;
+ }
+
+ // Removes the element at the given index. The size of the list is
+ // decreased by one.
+ //
+ public bool Remove(T item)
+ {
+ int index = IndexOf(item);
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
+ }
+
+ // This method removes all items which matches the predicate.
+ // The complexity is O(n).
+ public int RemoveAll(Predicate match)
+ {
+ if (match == null)
+ {
+ throw new ArgumentNullException(nameof(match));
+ }
+
+ int freeIndex = 0; // the first free slot in items array
+
+ // Find the first item which needs to be removed.
+ while (freeIndex < _size && !match(_items[freeIndex]!)) freeIndex++;
+ if (freeIndex >= _size) return 0;
+
+ int current = freeIndex + 1;
+ while (current < _size)
+ {
+ // Find the first item which needs to be kept.
+ while (current < _size && match(_items[current]!)) current++;
+
+ if (current < _size)
+ {
+ // copy item to the free slot.
+ _items[freeIndex++] = _items[current++];
+ }
+ }
+
+ Array.Clear(_items, freeIndex, _size - freeIndex);
+ int result = _size - freeIndex;
+ _size = freeIndex;
+ _version++;
+ return result;
+ }
+
+ // Removes the element at the given index. The size of the list is
+ // decreased by one.
+ //
+ public void RemoveAt(int index)
+ {
+ if ((uint)index >= (uint)_size)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+ _size--;
+ if (index < _size)
+ {
+ Array.Copy(_items, index + 1, _items, index, _size - index);
+ }
+ _items[_size] = default(T);
+ _version++;
+ }
+
+ // ToArray returns a new Object array containing the contents of the List.
+ // This requires copying the List, which is an O(n) operation.
+ public T[] ToArray()
+ {
+ T[] array = new T[_size];
+ Array.Copy(_items, 0, array, 0, _size);
+ return array;
+ }
+#endif
+ }
+
+#if !TYPE_LOADER_IMPLEMENTATION
+ // LowLevelList with full IList implementation
+ internal sealed class LowLevelListWithIList : LowLevelList, IList
+ {
+ public LowLevelListWithIList()
+ {
+ }
+
+ public LowLevelListWithIList(int capacity)
+ : base(capacity)
+ {
+ }
+
+ public LowLevelListWithIList(IEnumerable collection)
+ : base(collection)
+ {
+ }
+
+ // Is this List read-only?
+ bool ICollection.IsReadOnly
+ {
+ get { return false; }
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ private struct Enumerator : IEnumerator, System.Collections.IEnumerator
+ {
+ private LowLevelListWithIList _list;
+ private int _index;
+ private int _version;
+ private T? _current;
+
+ internal Enumerator(LowLevelListWithIList list)
+ {
+ _list = list;
+ _index = 0;
+ _version = list._version;
+ _current = default(T);
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ LowLevelListWithIList localList = _list;
+
+ if (_version == localList._version && ((uint)_index < (uint)localList._size))
+ {
+ _current = localList._items[_index];
+ _index++;
+ return true;
+ }
+ return MoveNextRare();
+ }
+
+ private bool MoveNextRare()
+ {
+ if (_version != _list._version)
+ {
+ throw new InvalidOperationException();
+ }
+
+ _index = _list._size + 1;
+ _current = default(T);
+ return false;
+ }
+
+ public T Current
+ {
+ get
+ {
+ return _current!;
+ }
+ }
+
+ object System.Collections.IEnumerator.Current
+ {
+ get
+ {
+ if (_index == 0 || _index == _list._size + 1)
+ {
+ throw new InvalidOperationException();
+ }
+ return Current;
+ }
+ }
+
+ void System.Collections.IEnumerator.Reset()
+ {
+ if (_version != _list._version)
+ {
+ throw new InvalidOperationException();
+ }
+
+ _index = 0;
+ _current = default(T);
+ }
+ }
+ }
+#endif // !TYPE_LOADER_IMPLEMENTATION
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs
new file mode 100644
index 00000000000000..f7d6a1d315f848
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceModeOnlyAttribute.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+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
new file mode 100644
index 00000000000000..f2e0d260b5d12a
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/DeveloperExperienceState.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace System.Runtime.CompilerServices
+{
+ [DeveloperExperienceModeOnly]
+ internal static class DeveloperExperienceState
+ {
+ public static bool DeveloperExperienceModeEnabled
+ {
+ get
+ {
+ return true; // ILC will rewrite to this "return false" if run with "/buildType:ret"
+ }
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockAllReflectionAttribute.cs b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockAllReflectionAttribute.cs
new file mode 100644
index 00000000000000..7e560e3f5a21c4
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockAllReflectionAttribute.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*
+ Providing a definition for __BlockAllReflectionAttribute in an assembly is a signal to the .NET Native toolchain
+ to remove the metadata for all APIs. This both reduces size and disables all reflection on those
+ APIs in libraries that include this.
+*/
+
+using System;
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.All)]
+ internal class __BlockAllReflectionAttribute : Attribute { }
+}
diff --git a/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockReflectionAttribute.cs b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockReflectionAttribute.cs
new file mode 100644
index 00000000000000..aba2c806f7171f
--- /dev/null
+++ b/src/coreclr/nativeaot/Common/src/System/Runtime/CompilerServices/__BlockReflectionAttribute.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*
+ Providing a definition for __BlockReflectionAttribute in an assembly is a signal to the .NET Native toolchain
+ to remove the metadata for all non-public APIs. This both reduces size and disables private reflection on those
+ APIs in libraries that include this.
+*/
+
+using System;
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.All)]
+ internal class __BlockReflectionAttribute : Attribute { }
+}
diff --git a/src/coreclr/nativeaot/Directory.Build.props b/src/coreclr/nativeaot/Directory.Build.props
new file mode 100644
index 00000000000000..8807dca0c847e7
--- /dev/null
+++ b/src/coreclr/nativeaot/Directory.Build.props
@@ -0,0 +1,120 @@
+
+
+
+
+ false
+
+
+
+ false
+ true
+ false
+ false
+ $(NetCoreAppCurrent)
+
+ Portable
+ true
+
+ $(RuntimeBinDir)/aotsdk/
+ Debug;Release;Checked
+ x64;x86;arm;arm64
+
+ $(TargetArchitecture)
+ arm
+ true
+
+ false
+
+ true
+ v4.0.30319
+ true
+ $(NoWarn),0419,0649,CA2249,CA1830
+
+
+ $(NoWarn);CS8600;CS8601;CS8602;CS8603;CS8604;CS8610;CS8618;CS8620;CS8625;CS8632;CS8765
+
+
+ $(NoWarn);CA1810;CA1823;CA1825;CA2208;SA1129;SA1205;SA1400;SA1517
+
+
+ $(NoWarn);CS3016
+
+
+ CORERT;NETCOREAPP
+
+ true
+
+ $(OutputPath)$(MSBuildProjectName).xml
+
+
+ $(IntermediateOutputPath)$(MSBuildProjectName).deps.json
+
+
+
+ false
+ true
+
+
+ FEATURE_COMINTEROP;$(DefineConstants)
+
+
+ false
+ true
+
+
+
+
+ x64
+ false
+ TARGET_64BIT;TARGET_AMD64;$(DefineConstants)
+
+
+ x86
+ TARGET_32BIT;$(DefineConstants)
+
+
+ arm
+ TARGET_32BIT;TARGET_ARM;$(DefineConstants)
+
+
+ AnyCPU
+ TARGET_64BIT;TARGET_ARM64;$(DefineConstants)
+
+
+
+ TARGET_WINDOWS;$(DefineConstants)
+ TARGET_UNIX;$(DefineConstants)
+
+
+
+
+ false
+ true
+ _LOGGING;DEBUG;$(DefineConstants)
+
+
+ true
+
+
+
+
+ $(AssemblyName)
+
+
+
+
+ true
+ SilverlightPlatform
+
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'Common', 'src'))
+ $(MSBuildThisFileDirectory)Common\src\
+ $(MSBuildThisFileDirectory)..\tools\Common\
+
+
+
+
diff --git a/src/coreclr/nativeaot/Directory.Build.targets b/src/coreclr/nativeaot/Directory.Build.targets
new file mode 100644
index 00000000000000..0572326e695aec
--- /dev/null
+++ b/src/coreclr/nativeaot/Directory.Build.targets
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ false
+
+
+
+
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/AsmOffsets.cspp b/src/coreclr/nativeaot/Runtime.Base/src/AsmOffsets.cspp
new file mode 100644
index 00000000000000..27d0035ae47d86
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/AsmOffsets.cspp
@@ -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.
+
+#define PLAT_ASM_OFFSET(offset, cls, member) internal const int OFFSETOF__##cls##__##member = 0x##offset;
+#define PLAT_ASM_SIZEOF(offset, cls) internal const int SIZEOF__##cls = 0x##offset;
+#define PLAT_ASM_CONST(constant, expr) internal const int expr = 0x##constant;
+
+static class AsmOffsets
+{
+#include "../../Runtime/AsmOffsets.h"
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/Internal/Runtime/CompilerServices/Unsafe.cs b/src/coreclr/nativeaot/Runtime.Base/src/Internal/Runtime/CompilerServices/Unsafe.cs
new file mode 100644
index 00000000000000..a66ee4ce7c0da7
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/Internal/Runtime/CompilerServices/Unsafe.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Internal.Runtime.CompilerServices
+{
+ //
+ // Subsetted clone of System.Runtime.CompilerServices.Unsafe for internal runtime use.
+ // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe.
+ //
+
+ ///
+ /// Contains generic, low-level functionality for manipulating pointers.
+ ///
+ public static unsafe class Unsafe
+ {
+ ///
+ /// Returns a pointer to the given by-ref parameter.
+ ///
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void* AsPointer(ref T value)
+ {
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // conv.u
+ // ret
+ }
+
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SizeOf()
+ {
+ // This method is implemented by the toolchain
+ throw new PlatformNotSupportedException();
+
+ // sizeof !!0
+ // ret
+ }
+
+ ///
+ /// Casts the given object to the specified type, performs no dynamic type checking.
+ ///
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T As(object value) where T : class
+ {
+ // This method is implemented by the toolchain
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // ret
+ }
+
+ ///
+ /// Reinterprets the given reference as a reference to a value of type .
+ ///
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref TTo As(ref TFrom source)
+ {
+ // This method is implemented by the toolchain
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // ret
+ }
+
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AddByteOffset(ref T source, IntPtr byteOffset)
+ {
+ // This method is implemented by the toolchain
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // ldarg.1
+ // add
+ // ret
+ }
+
+ ///
+ /// Adds an element offset to the given reference.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T Add(ref T source, int elementOffset)
+ {
+ return ref AddByteOffset(ref source, (IntPtr)(elementOffset * (nint)SizeOf()));
+ }
+
+ ///
+ /// Reinterprets the given location as a reference to a value of type .
+ ///
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(in T source)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/RhBaseName.cs b/src/coreclr/nativeaot/Runtime.Base/src/RhBaseName.cs
new file mode 100644
index 00000000000000..2c2189c7d8bf49
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/RhBaseName.cs
@@ -0,0 +1,4 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+internal static class Redhawk { public const string BaseName = "*"; }
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs
new file mode 100644
index 00000000000000..e6f4b12ba86b7e
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+ // CONTRACT with Runtime
+ // The Array type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type int
+
+ public partial class Array
+ {
+ // CS0169: The field 'Array._numComponents' is never used
+#pragma warning disable 0169
+ // This field should be the first field in Array as the runtime/compilers depend on it
+ private int _numComponents;
+#pragma warning restore
+
+ public int Length => (int)Unsafe.As(this).Length;
+ }
+
+ // To accommodate class libraries that wish to implement generic interfaces on arrays, all class libraries
+ // are now required to provide an Array class that derives from Array.
+ internal class Array : Array
+ {
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal class RawArrayData
+ {
+ public uint Length; // Array._numComponents padded to IntPtr
+#if BIT64
+ public uint Padding;
+#endif
+ public byte Data;
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Attribute.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Attribute.cs
new file mode 100644
index 00000000000000..0ab0cf95225f0d
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Attribute.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System
+{
+ [AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
+ public abstract class Attribute
+ {
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeTargets.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeTargets.cs
new file mode 100644
index 00000000000000..37f5d151709e85
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeTargets.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System
+{
+ // Enum used to indicate all the elements of the
+ // VOS it is valid to attach this element to.
+
+ internal enum AttributeTargets
+ {
+ Assembly = 0x0001,
+ Module = 0x0002,
+ Class = 0x0004,
+ Struct = 0x0008,
+ Enum = 0x0010,
+ Constructor = 0x0020,
+ Method = 0x0040,
+ Property = 0x0080,
+ Field = 0x0100,
+ Event = 0x0200,
+ Interface = 0x0400,
+ Parameter = 0x0800,
+ Delegate = 0x1000,
+ ReturnValue = 0x2000,
+ GenericParameter = 0x4000,
+
+ All = Assembly | Module | Class | Struct | Enum | Constructor |
+ Method | Property | Field | Event | Interface | Parameter |
+ Delegate | ReturnValue | GenericParameter
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeUsageAttribute.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeUsageAttribute.cs
new file mode 100644
index 00000000000000..bd9ef45df75207
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/AttributeUsageAttribute.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*============================================================
+**
+**
+**
+** Purpose: The class denotes how to specify the usage of an attribute
+**
+**
+===========================================================*/
+
+namespace System
+{
+ /* By default, attributes are inherited and multiple attributes are not allowed */
+ [AttributeUsage(AttributeTargets.Class, Inherited = true)]
+ internal sealed class AttributeUsageAttribute : Attribute
+ {
+ //Constructors
+ public AttributeUsageAttribute(AttributeTargets validOn)
+ {
+ }
+
+ public AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited)
+ {
+ }
+
+ //Properties.
+ // Allowing the set properties as it allows a more readable syntax in the specifiers (and are commonly used)
+ // The get properties will be needed only if these attributes are used at Runtime, however, the compiler
+ // is getting an internal error if the gets are not defined.
+
+ public bool AllowMultiple
+ {
+ get { return false; }
+ set { }
+ }
+
+ public bool Inherited
+ {
+ get { return false; }
+ set { }
+ }
+ }
+}
diff --git a/src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.cpp b/src/coreclr/nativeaot/Runtime.Base/src/System/Delegate.cs
similarity index 51%
rename from src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.cpp
rename to src/coreclr/nativeaot/Runtime.Base/src/System/Delegate.cs
index 997542f41025a8..bf63352b06e235 100644
--- a/src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.cpp
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Delegate.cs
@@ -1,6 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#include "pch.h"
+using System.Runtime;
+using System.Runtime.InteropServices;
-// Bei der Verwendung vorkompilierter Header ist diese Quelldatei für eine erfolgreiche Kompilierung erforderlich.
+namespace System
+{
+ public class Delegate
+ {
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/ConditionalAttribute.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/ConditionalAttribute.cs
new file mode 100644
index 00000000000000..de79c774c57b54
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/ConditionalAttribute.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Diagnostics
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
+ internal sealed class ConditionalAttribute : Attribute
+ {
+ public ConditionalAttribute(string conditionString)
+ {
+ _conditionString = conditionString;
+ }
+
+ public string ConditionString
+ {
+ get
+ {
+ return _conditionString;
+ }
+ }
+
+ private string _conditionString;
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/Debug.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/Debug.cs
new file mode 100644
index 00000000000000..0221b8e7c98951
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Diagnostics/Debug.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime;
+using System.Runtime.CompilerServices;
+
+namespace System.Diagnostics
+{
+ internal static class Debug
+ {
+ [System.Diagnostics.Conditional("DEBUG")]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Assert(bool condition, string message)
+ {
+ if (!condition)
+ {
+ EH.FallbackFailFast(RhFailFastReason.InternalError, null);
+ }
+ }
+
+ [System.Diagnostics.Conditional("DEBUG")]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Assert(bool condition)
+ {
+ if (!condition)
+ {
+ EH.FallbackFailFast(RhFailFastReason.InternalError, null);
+ }
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs
new file mode 100644
index 00000000000000..f3851d38d7833f
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace System
+{
+ public abstract class Exception
+ {
+ private string _exceptionString;
+
+ public Exception() { }
+
+ public Exception(string str)
+ {
+ _exceptionString = str;
+ }
+ }
+
+ internal sealed class NullReferenceException : Exception
+ {
+ public NullReferenceException() { }
+ }
+
+ internal sealed class InvalidOperationException : Exception
+ {
+ public InvalidOperationException() { }
+ }
+
+ internal sealed class ArgumentOutOfRangeException : Exception
+ {
+ public ArgumentOutOfRangeException() { }
+ }
+
+ internal sealed class IndexOutOfRangeException : Exception
+ {
+ public IndexOutOfRangeException() { }
+ }
+
+ internal sealed class ArgumentNullException : Exception
+ {
+ public ArgumentNullException() { }
+ }
+
+ internal sealed class NotImplementedException : Exception
+ {
+ public NotImplementedException() { }
+ }
+
+ internal sealed class NotSupportedException : Exception
+ {
+ public NotSupportedException() { }
+ }
+
+ internal sealed class PlatformNotSupportedException : Exception
+ {
+ public PlatformNotSupportedException() { }
+ }
+
+ internal sealed class InvalidCastException : Exception
+ {
+ public InvalidCastException() { }
+ }
+
+ internal sealed class ArrayTypeMismatchException : Exception
+ {
+ public ArrayTypeMismatchException() { }
+ }
+
+ internal sealed class OverflowException : Exception
+ {
+ public OverflowException() { }
+ }
+
+ internal sealed class ArithmeticException : Exception
+ {
+ public ArithmeticException() { }
+ }
+
+ internal sealed class DivideByZeroException : Exception
+ {
+ public DivideByZeroException() { }
+ }
+
+ internal class OutOfMemoryException : Exception
+ {
+ public OutOfMemoryException() { }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/FlagsAttribute.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/FlagsAttribute.cs
new file mode 100644
index 00000000000000..fd33dcf19f81a8
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/FlagsAttribute.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System
+{
+ // Custom attribute to indicate that the enum
+ // should be treated as a bitfield (or set of flags).
+ // An IDE may use this information to provide a richer
+ // development experience.
+ [AttributeUsage(AttributeTargets.Enum, Inherited = false)]
+ public class FlagsAttribute : Attribute
+ {
+ public FlagsAttribute()
+ {
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/GC.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/GC.cs
new file mode 100644
index 00000000000000..fea06c6123be6e
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/GC.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+// Exposes features of the Garbage Collector to managed code.
+//
+// This is an extremely simple initial version that only exposes a small fraction of the API that the CLR
+// version does.
+//
+
+namespace System
+{
+ // !!!!!!!!!!!!!!!!!!!!!!!
+ // Make sure you change the def in gc.h if you change this!
+ public enum InternalGCCollectionMode
+ {
+ NonBlocking = 0x00000001,
+ Blocking = 0x00000002,
+ Optimized = 0x00000004,
+ }
+
+ public enum GCLatencyMode
+ {
+ Batch = 0,
+ Interactive = 1,
+ LowLatency = 2,
+ SustainedLowLatency = 3
+ }
+}
diff --git a/src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.h b/src/coreclr/nativeaot/Runtime.Base/src/System/MulticastDelegate.cs
similarity index 56%
rename from src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.h
rename to src/coreclr/nativeaot/Runtime.Base/src/System/MulticastDelegate.cs
index 8ea9a9f7b04182..89ca1daa25c0a7 100644
--- a/src/coreclr/tools/StressLogAnalyzer/StressLogPlugin/pch.h
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/MulticastDelegate.cs
@@ -1,8 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#ifndef PCH_H
-#define PCH_H
+using System.Runtime;
-// Fügen Sie hier Header hinzu, die vorkompiliert werden sollen.
-#endif //PCH_H
+namespace System
+{
+ public class MulticastDelegate : Delegate
+ {
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Nullable.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Nullable.cs
new file mode 100644
index 00000000000000..2f43b9b7515eb9
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Nullable.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace System
+{
+ internal struct Nullable where T : struct
+ {
+#pragma warning disable 169 // The field 'blah' is never used
+ private readonly bool _hasValue;
+ private T _value;
+#pragma warning restore 0169
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Object.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Object.cs
new file mode 100644
index 00000000000000..c64cd5000fe8dc
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Object.cs
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+
+using Internal.Runtime;
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+ // CONTRACT with Runtime
+ // The Object type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type MethodTable*
+ // VTable Contract: The first vtable slot should be the finalizer for object => The first virtual method in the object class should be the Finalizer
+
+ public unsafe class Object
+ {
+ // CS0649: Field '{blah}' is never assigned to, and will always have its default value
+#pragma warning disable 649
+ private MethodTable* m_pEEType;
+#pragma warning restore
+
+ // Creates a new instance of an Object.
+ public Object()
+ {
+ }
+
+ // Allow an object to free resources before the object is reclaimed by the GC.
+ // CONTRACT with runtime: This method's virtual slot number is hardcoded in the binder. It is an
+ // implementation detail where it winds up at runtime.
+ // **** Do not add any virtual methods in this class ahead of this ****
+
+ ~Object()
+ {
+ }
+
+ internal MethodTable* MethodTable
+ {
+ get
+ {
+ // NOTE: if managed code can be run when the GC has objects marked, then this method is
+ // unsafe. But, generically, we don't expect managed code such as this to be allowed
+ // to run while the GC is running.
+ return m_pEEType;
+ }
+ }
+
+ [Runtime.CompilerServices.Intrinsic]
+ internal static extern MethodTable* MethodTableOf();
+
+ internal EETypePtr EETypePtr
+ {
+ get
+ {
+ return new EETypePtr(new IntPtr(m_pEEType));
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private class RawData
+ {
+ public byte Data;
+ }
+
+ ///
+ /// Return beginning of all data (excluding ObjHeader and MethodTable*) within this object.
+ /// Note that for strings/arrays this would include the Length as well.
+ ///
+ internal ref byte GetRawData()
+ {
+ return ref Unsafe.As(this).Data;
+ }
+
+ ///
+ /// Return size of all data (excluding ObjHeader and MethodTable*).
+ /// Note that for strings/arrays this would include the Length as well.
+ ///
+ internal uint GetRawDataSize()
+ {
+ return EETypePtr.BaseSize - (uint)sizeof(ObjHeader) - (uint)sizeof(MethodTable*);
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/ParamArrayAttribute.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/ParamArrayAttribute.cs
new file mode 100644
index 00000000000000..3bc2f7847effec
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/ParamArrayAttribute.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System
+{
+ // Attribute to indicate array of arguments for variable number of args.
+
+ [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
+ internal class ParamArrayAttribute : Attribute
+ {
+ public ParamArrayAttribute()
+ {
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Primitives.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Primitives.cs
new file mode 100644
index 00000000000000..52dffcfdb8c59e
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Primitives.cs
@@ -0,0 +1,534 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This file contains the basic primitive type definitions (int etc)
+// These types are well known to the compiler and the runtime and are basic interchange types that do not change
+
+// CONTRACT with Runtime
+// Each of the data types has a data contract with the runtime. See the contract in the type definition
+//
+
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ // CONTRACT with Runtime
+ // Place holder type for type hierarchy, Compiler/Runtime requires this class
+ public abstract class ValueType
+ {
+ }
+
+ // CONTRACT with Runtime, Compiler/Runtime requires this class
+ // Place holder type for type hierarchy
+ public abstract class Enum : ValueType
+ {
+ }
+
+ /*============================================================
+ **
+ ** Class: Boolean
+ **
+ **
+ ** Purpose: The boolean class serves as a wrapper for the primitive
+ ** type boolean.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Boolean type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type bool
+
+ public struct Boolean
+ {
+ // Disable compile warning about unused _value field
+#pragma warning disable 0169
+ private bool _value;
+#pragma warning restore 0169
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Char
+ **
+ **
+ ** Purpose: This is the value class representing a Unicode character
+ **
+ **
+ ===========================================================*/
+
+
+ // CONTRACT with Runtime
+ // The Char type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type char
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Char
+ {
+ private char _value;
+
+ public const char MaxValue = (char)0xFFFF;
+ public const char MinValue = (char)0x00;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: SByte
+ **
+ **
+ ** Purpose: A representation of a 8 bit 2's complement integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The SByte type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type sbyte
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SByte
+ {
+ private sbyte _value;
+
+ public const sbyte MaxValue = (sbyte)0x7F;
+ public const sbyte MinValue = unchecked((sbyte)0x80);
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Byte
+ **
+ **
+ ** Purpose: A representation of a 8 bit integer (byte)
+ **
+ **
+ ===========================================================*/
+
+
+ // CONTRACT with Runtime
+ // The Byte type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type bool
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Byte
+ {
+ private byte _value;
+
+ public const byte MaxValue = (byte)0xFF;
+ public const byte MinValue = 0;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Int16
+ **
+ **
+ ** Purpose: A representation of a 16 bit 2's complement integer.
+ **
+ **
+ ===========================================================*/
+
+
+ // CONTRACT with Runtime
+ // The Int16 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type short
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Int16
+ {
+ private short _value;
+
+ public const short MaxValue = (short)0x7FFF;
+ public const short MinValue = unchecked((short)0x8000);
+ }
+
+ /*============================================================
+ **
+ ** Class: UInt16
+ **
+ **
+ ** Purpose: A representation of a short (unsigned 16-bit) integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Uint16 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type ushort
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct UInt16
+ {
+ private ushort _value;
+
+ public const ushort MaxValue = (ushort)0xffff;
+ public const ushort MinValue = 0;
+ }
+
+ /*============================================================
+ **
+ ** Class: Int32
+ **
+ **
+ ** Purpose: A representation of a 32 bit 2's complement integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Int32 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type int
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Int32
+ {
+ private int _value;
+
+ public const int MaxValue = 0x7fffffff;
+ public const int MinValue = unchecked((int)0x80000000);
+ }
+
+
+ /*============================================================
+ **
+ ** Class: UInt32
+ **
+ **
+ ** Purpose: A representation of a 32 bit unsigned integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Uint32 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type uint
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct UInt32
+ {
+ private uint _value;
+
+ public const uint MaxValue = (uint)0xffffffff;
+ public const uint MinValue = 0;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Int64
+ **
+ **
+ ** Purpose: A representation of a 64 bit 2's complement integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Int64 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type long
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Int64
+ {
+ private long _value;
+
+ public const long MaxValue = 0x7fffffffffffffffL;
+ public const long MinValue = unchecked((long)0x8000000000000000L);
+ }
+
+
+ /*============================================================
+ **
+ ** Class: UInt64
+ **
+ **
+ ** Purpose: A representation of a 64 bit unsigned integer.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The UInt64 type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type ulong
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct UInt64
+ {
+ private ulong _value;
+
+ public const ulong MaxValue = (ulong)0xffffffffffffffffL;
+ public const ulong MinValue = 0;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Single
+ **
+ **
+ ** Purpose: A wrapper class for the primitive type float.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Single type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type float
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Single
+ {
+ private float _value;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: Double
+ **
+ **
+ ** Purpose: A representation of an IEEE double precision
+ ** floating point number.
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The Double type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type double
+ // This type is LayoutKind Sequential
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Double
+ {
+ private double _value;
+ }
+
+
+ /*============================================================
+ **
+ ** Class: IntPtr
+ **
+ **
+ ** Purpose: Platform independent integer
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The IntPtr type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type void *
+
+ // This type implements == without overriding GetHashCode, Equals, disable compiler warning
+#pragma warning disable 0660, 0661
+ public struct IntPtr
+ {
+ private unsafe void* _value; // The compiler treats void* closest to uint hence explicit casts are required to preserve int behavior
+
+ [Intrinsic]
+ public static readonly IntPtr Zero;
+
+ public static unsafe int Size
+ {
+ [Intrinsic]
+ get
+ {
+#if TARGET_64BIT
+ return 8;
+#else
+ return 4;
+#endif
+ }
+ }
+
+ [Intrinsic]
+ public unsafe IntPtr(void* value)
+ {
+ _value = value;
+ }
+
+ [Intrinsic]
+ public unsafe IntPtr(int value)
+ {
+ _value = (void*)value;
+ }
+
+ [Intrinsic]
+ public unsafe IntPtr(long value)
+ {
+ _value = (void*)value;
+ }
+
+ [Intrinsic]
+ public unsafe long ToInt64()
+ {
+#if TARGET_64BIT
+ return (long)_value;
+#else
+ return (long)(int)_value;
+#endif
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator IntPtr(int value)
+ {
+ return new IntPtr(value);
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator IntPtr(long value)
+ {
+ return new IntPtr(value);
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator IntPtr(void* value)
+ {
+ return new IntPtr(value);
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator void* (IntPtr value)
+ {
+ return value._value;
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator int(IntPtr value)
+ {
+ return unchecked((int)value._value);
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator long(IntPtr value)
+ {
+ return unchecked((long)value._value);
+ }
+
+ [Intrinsic]
+ public static unsafe bool operator ==(IntPtr value1, IntPtr value2)
+ {
+ return value1._value == value2._value;
+ }
+
+ [Intrinsic]
+ public static unsafe bool operator !=(IntPtr value1, IntPtr value2)
+ {
+ return value1._value != value2._value;
+ }
+
+ [Intrinsic]
+ public static unsafe IntPtr operator +(IntPtr pointer, int offset)
+ {
+#if TARGET_64BIT
+ return new IntPtr((long)pointer._value + offset);
+#else
+ return new IntPtr((int)pointer._value + offset);
+#endif
+ }
+ }
+#pragma warning restore 0660, 0661
+
+
+ /*============================================================
+ **
+ ** Class: UIntPtr
+ **
+ **
+ ** Purpose: Platform independent integer
+ **
+ **
+ ===========================================================*/
+
+ // CONTRACT with Runtime
+ // The UIntPtr type is one of the primitives understood by the compilers and runtime
+ // Data Contract: Single field of type void *
+
+ // This type implements == without overriding GetHashCode, Equals, disable compiler warning
+#pragma warning disable 0660, 0661
+ public struct UIntPtr
+ {
+ private unsafe void* _value;
+
+ [Intrinsic]
+ public static readonly UIntPtr Zero;
+
+ [Intrinsic]
+ public unsafe UIntPtr(uint value)
+ {
+ _value = (void*)value;
+ }
+
+ [Intrinsic]
+ public unsafe UIntPtr(ulong value)
+ {
+#if TARGET_64BIT
+ _value = (void*)value;
+#else
+ _value = (void*)checked((uint)value);
+#endif
+ }
+
+ [Intrinsic]
+ public unsafe UIntPtr(void* value)
+ {
+ _value = value;
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator UIntPtr(void* value)
+ {
+ return new UIntPtr(value);
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator void* (UIntPtr value)
+ {
+ return value._value;
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator uint (UIntPtr value)
+ {
+#if TARGET_64BIT
+ return checked((uint)value._value);
+#else
+ return (uint)value._value;
+#endif
+ }
+
+ [Intrinsic]
+ public static unsafe explicit operator ulong (UIntPtr value)
+ {
+ return (ulong)value._value;
+ }
+
+ [Intrinsic]
+ public static unsafe bool operator ==(UIntPtr value1, UIntPtr value2)
+ {
+ return value1._value == value2._value;
+ }
+
+ [Intrinsic]
+ public static unsafe bool operator !=(UIntPtr value1, UIntPtr value2)
+ {
+ return value1._value != value2._value;
+ }
+ }
+#pragma warning restore 0660, 0661
+}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
new file mode 100644
index 00000000000000..6946733ebdf9f0
--- /dev/null
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
@@ -0,0 +1,151 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+
+using Internal.Runtime;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Runtime
+{
+ internal static unsafe class CachedInterfaceDispatch
+ {
+ [RuntimeExport("RhpCidResolve")]
+ private static unsafe IntPtr RhpCidResolve(IntPtr callerTransitionBlockParam, IntPtr pCell)
+ {
+ IntPtr locationOfThisPointer = callerTransitionBlockParam + TransitionBlock.GetThisOffset();
+ object pObject = Unsafe.As(ref *(IntPtr*)locationOfThisPointer);
+ IntPtr dispatchResolveTarget = RhpCidResolve_Worker(pObject, pCell);
+ return dispatchResolveTarget;
+ }
+
+ private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
+ {
+ DispatchCellInfo cellInfo;
+
+ InternalCalls.RhpGetDispatchCellInfo(pCell, out cellInfo);
+ IntPtr pTargetCode = RhResolveDispatchWorker(pObject, (void*)pCell, ref cellInfo);
+ if (pTargetCode != IntPtr.Zero)
+ {
+ // We don't update the dispatch cell cache if this is IDynamicInterfaceCastable because this
+ // scenario is by-design dynamic. There is no guarantee that another instance with the same MethodTable
+ // as the one we just resolved would do the resolution the same way. We will need to ask again.
+ if (!pObject.MethodTable->IsIDynamicInterfaceCastable)
+ {
+ return InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.MethodTable, ref cellInfo);
+ }
+ else
+ {
+ return pTargetCode;
+ }
+ }
+
+ // "Valid method implementation was not found."
+ EH.FallbackFailFast(RhFailFastReason.InternalError, null);
+ return IntPtr.Zero;
+ }
+
+ [RuntimeExport("RhpResolveInterfaceMethod")]
+ private static IntPtr RhpResolveInterfaceMethod(object pObject, IntPtr pCell)
+ {
+ if (pObject == null)
+ {
+ // ProjectN Optimizer may perform code motion on dispatch such that it occurs independant of
+ // null check on "this" pointer. Allow for this case by returning back an invalid pointer.
+ return IntPtr.Zero;
+ }
+
+ MethodTable* pInstanceType = pObject.MethodTable;
+
+ // This method is used for the implementation of LOAD_VIRT_FUNCTION and in that case the mapping we want
+ // may already be in the cache.
+ IntPtr pTargetCode = InternalCalls.RhpSearchDispatchCellCache(pCell, pInstanceType);
+ if (pTargetCode == IntPtr.Zero)
+ {
+ // Otherwise call the version of this method that knows how to resolve the method manually.
+ pTargetCode = RhpCidResolve_Worker(pObject, pCell);
+ }
+
+ return pTargetCode;
+ }
+
+ [RuntimeExport("RhResolveDispatch")]
+ private static IntPtr RhResolveDispatch(object pObject, EETypePtr interfaceType, ushort slot)
+ {
+ DispatchCellInfo cellInfo = default;
+ cellInfo.CellType = DispatchCellType.InterfaceAndSlot;
+ cellInfo.InterfaceType = interfaceType;
+ cellInfo.InterfaceSlot = slot;
+
+ return RhResolveDispatchWorker(pObject, null, ref cellInfo);
+ }
+
+ [RuntimeExport("RhResolveDispatchOnType")]
+ private static IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot)
+ {
+ // Type of object we're dispatching on.
+ MethodTable* pInstanceType = instanceType.ToPointer();
+
+ // Type of interface
+ MethodTable* pInterfaceType = interfaceType.ToPointer();
+
+ return DispatchResolve.FindInterfaceMethodImplementationTarget(pInstanceType,
+ pInterfaceType,
+ slot);
+ }
+
+ private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void* cell, ref DispatchCellInfo cellInfo)
+ {
+ // Type of object we're dispatching on.
+ MethodTable* pInstanceType = pObject.MethodTable;
+
+ if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot)
+ {
+ // Type whose DispatchMap is used. Usually the same as the above but for types which implement IDynamicInterfaceCastable
+ // we may repeat this process with an alternate type.
+ MethodTable* pResolvingInstanceType = pInstanceType;
+
+ IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
+ cellInfo.InterfaceType.ToPointer(),
+ cellInfo.InterfaceSlot);
+ if (pTargetCode == IntPtr.Zero && pInstanceType->IsIDynamicInterfaceCastable)
+ {
+ // Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable
+ // This will either give us the appropriate result, or throw.
+ var pfnGetInterfaceImplementation = (delegate*