diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 5e9013310e4e9..d731c6dd1f16d 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.21501.2",
+ "version": "1.0.0-prerelease.21511.3",
"commands": [
"xharness"
]
diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml
index ee28f6b233a15..4aa6545ec43bd 100644
--- a/.github/ISSUE_TEMPLATE/01_bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml
@@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
- We welcome bug reports! Please see our [contribution guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md) for more information on writing a good bug report. This template will help us gather the information we need to start the triage process.
+ We welcome bug reports! Please see our [contribution guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md#writing-a-good-bug-report) for more information on writing a good bug report. This template will help us gather the information we need to start the triage process.
- type: textarea
id: background
attributes:
diff --git a/.github/ISSUE_TEMPLATE/02_api_proposal.yml b/.github/ISSUE_TEMPLATE/02_api_proposal.yml
index 1462b38ad80d4..145095e3bb42b 100644
--- a/.github/ISSUE_TEMPLATE/02_api_proposal.yml
+++ b/.github/ISSUE_TEMPLATE/02_api_proposal.yml
@@ -55,6 +55,15 @@ body:
```
validations:
required: true
+ - type: textarea
+ id: alternative-designs
+ attributes:
+ label: Alternative Designs
+ description: |
+ Please provide alternative designs. This might not be APIs; for example instead of providing new APIs an option might be to change the behavior of an existing API.
+ placeholder: Alternative designs
+ validations:
+ required: false
- type: textarea
id: risks
attributes:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0b5c363bdc32c..9b87e2ce453d9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,9 +1,63 @@
-Contribution to .NET Runtime
-=====================
+# Contribution to .NET Runtime
You can contribute to .NET Runtime with issues and PRs. Simply filing issues for problems you encounter is a great way to contribute. Contributing implementations is greatly appreciated.
-## Contribution "Bar"
+## Reporting Issues
+
+We always welcome bug reports, API proposals and overall feedback. Here are a few tips on how you can make reporting your issue as effective as possible.
+
+### Identify Where to Report
+
+The .NET codebase is distributed across multiple repositories in the [dotnet organization](https://github.com/dotnet). Depending on the feedback you might want to file the issue on a different repo. Here are a few common repos:
+
+* [dotnet/runtime](https://github.com/dotnet/runtime) .NET runtime, libraries and shared host installers.
+* [dotnet/roslyn](https://github.com/dotnet/roslyn) C# and VB compiler.
+* [dotnet/aspnetcore](https://github.com/dotnet/aspnetcore) ASP.NET Core.
+* [dotnet/core](https://github.com/dotnet/core) Can be used to submit feedback if not sure what repo to use.
+
+### Finding Existing Issues
+
+Before filing a new issue, please search our [open issues](https://github.com/dotnet/runtime/issues) to check if it already exists.
+
+If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
+
+### Writing a Good API Proposal
+
+Please review our [API review process](https://github.com/dotnet/runtime/blob/main/docs/project/api-review-process.md) documents for guidelines on how to submit an API review. When ready to submit a proposal, please use the [API Suggestion issue template](https://github.com/dotnet/runtime/issues/new?assignees=&labels=api-suggestion&template=02_api_proposal.yml&title=%5BAPI+Proposal%5D%3A+).
+
+### Writing a Good Bug Report
+
+Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved. Ideally, a bug report should contain the following information:
+
+* A high-level description of the problem.
+* A _minimal reproduction_, i.e. the smallest size of code/configuration required to reproduce the wrong behavior.
+* A description of the _expected behavior_, contrasted with the _actual behavior_ observed.
+* Information on the environment: OS/distro, CPU arch, SDK version, etc.
+* Additional information, e.g. is it a regression from previous versions? are there any known workarounds?
+
+When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/dotnet/runtime/issues/new?assignees=&labels=&template=01_bug_report.yml).
+
+#### Why are Minimal Reproductions Important?
+
+A reproduction lets maintainers verify the presence of a bug, and diagnose the issue using a debugger. A _minimal_ reproduction is the smallest possible console application demonstrating that bug. Minimal reproductions are generally preferable since they:
+
+1. Focus debugging efforts on a simple code snippet,
+2. Ensure that the problem is not caused by unrelated dependencies/configuration,
+3. Avoid the need to share production codebases.
+
+#### Are Minimal Reproductions Required?
+
+In certain cases, creating a minimal reproduction might not be practical (e.g. due to nondeterministic factors, external dependencies). In such cases you would be asked to provide as much information as possible, for example by sharing a memory dump of the failing application. If maintainers are unable to root cause the problem, they might still close the issue as not actionable. While not required, minimal reproductions are strongly encouraged and will significantly improve the chances of your issue being prioritized and fixed by the maintainers.
+
+#### How to Create a Minimal Reproduction
+
+The best way to create a minimal reproduction is gradually removing code and dependencies from a reproducing app, until the problem no longer occurs. A good minimal reproduction:
+
+* Excludes all unnecessary types, methods, code blocks, source files, nuget dependencies and project configurations.
+* Contains documentation or code comments illustrating expected vs actual behavior.
+* If possible, avoids performing any unneeded IO or system calls. For example, can the ASP.NET based reproduction be converted to a plain old console app?
+
+## Contributing Changes
Project maintainers will merge changes that improve the product significantly and broadly align with the [.NET Roadmap](https://github.com/dotnet/core/blob/master/roadmap.md).
@@ -11,7 +65,7 @@ Maintainers will not merge changes that have narrowly-defined benefits, due to c
Contributions must also satisfy the other published guidelines defined in this document.
-## DOs and DON'Ts
+### DOs and DON'Ts
Please do:
@@ -33,11 +87,11 @@ Please do not:
* **DON'T** submit PRs that alter licensing related files or headers. If you believe there's a problem with them, file an issue and we'll be happy to discuss it.
* **DON'T** add API additions without filing an issue and discussing with us first. See [API Review Process](docs/project/api-review-process.md).
-## Breaking Changes
+### Breaking Changes
Contributions must maintain [API signature](docs/coding-guidelines/breaking-changes.md#bucket-1-public-contract) and behavioral compatibility. Contributions that include [breaking changes](docs/coding-guidelines/breaking-changes.md) will be rejected. Please file an issue to discuss your idea or change if you believe that it may affect managed code compatibility.
-## Suggested Workflow
+### Suggested Workflow
We use and recommend the following workflow:
@@ -67,11 +121,11 @@ We use and recommend the following workflow:
- The next official build will automatically include your change.
- You can delete the branch you used for making the change.
-## Up for Grabs
+### Up for Grabs
The team marks the most straightforward issues as [up for grabs](https://github.com/dotnet/runtime/labels/up-for-grabs). This set of issues is the place to start if you are interested in contributing but new to the codebase.
-## Commit Messages
+### Commit Messages
Please format commit messages as follows (based on [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)):
@@ -90,7 +144,7 @@ Fix #42
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
-## Contributor License Agreement
+### Contributor License Agreement
You must sign a [.NET Foundation Contribution License Agreement (CLA)](https://cla.dotnetfoundation.org) before your PR will be merged. This is a one-time requirement for projects in the .NET Foundation. You can read more about [Contribution License Agreements (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) on Wikipedia.
@@ -98,7 +152,7 @@ The agreement: [net-foundation-contribution-license-agreement.pdf](https://githu
You don't have to do this up-front. You can simply clone, fork, and submit your pull-request as usual. When your pull-request is created, it is classified by a CLA bot. If the change is trivial (for example, you just fixed a typo), then the PR is labelled with `cla-not-required`. Otherwise it's classified as `cla-required`. Once you signed a CLA, the current and all future pull-requests will be labelled as `cla-signed`.
-## File Headers
+### File Headers
The following file header is the used for .NET Core. Please use it for new files.
@@ -110,13 +164,13 @@ The following file header is the used for .NET Core. Please use it for new files
- See [class.cpp](./src/coreclr/vm/class.cpp) for an example of the header in a C++ file.
- See [List.cs](./src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs) for an example of the header in a C# file.
-## PR - CI Process
+### PR - CI Process
The [dotnet continuous integration](https://dev.azure.com/dnceng/public/) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean.
If the CI build fails for any reason, the PR issue will be updated with a link that can be used to determine the cause of the failure.
-## PR Feedback
+### PR Feedback
Microsoft team and community members will provide feedback on your change. Community feedback is highly valued. You will often see the absence of team feedback if the community has already provided good review feedback.
@@ -124,7 +178,7 @@ One or more Microsoft team members will review every PR prior to merge. They wil
There are lots of thoughts and [approaches](https://github.com/antlr/antlr4-cpp/blob/master/CONTRIBUTING.md#emoji) for how to efficiently discuss changes. It is best to be clear and explicit with your feedback. Please be patient with people who might not understand the finer details about your approach to feedback.
-## Contributing Ports
+### Contributing Ports
We encourage ports of CoreCLR to other platforms. There are multiple ports ongoing at any one time. You may be interested in one of the following ports:
@@ -145,7 +199,7 @@ Note: Add links to install instructions for each of these ports.
Ports have a weaker contribution bar, at least initially. A functionally correct implementation is considered an important first goal. Performance, reliability and compatibility are all important concerns after that.
-### Copying Files from Other Projects
+#### Copying Files from Other Projects
.NET Core uses some files from other projects, typically where a binary distribution does not exist or would be inconvenient.
@@ -157,7 +211,7 @@ The following rules must be followed for PRs that include files from another pro
See [IdnMapping.cs](./src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs) for an example of a file copied from another project and attributed in the [CoreCLR 3rd party notices](./THIRD-PARTY-NOTICES.TXT) file.
-### Porting Files from Other Projects
+#### Porting Files from Other Projects
There are many good algorithms implemented in other languages that would benefit the .NET Core project. The rules for porting a Java file to C#, for example, are the same as would be used for copying the same file, as described above.
diff --git a/Directory.Build.props b/Directory.Build.props
index 42d713f8e0d22..92bcbf935a9c5 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -62,6 +62,8 @@
net462
net472
+
+
diff --git a/README.md b/README.md
index 1444df567a8e1..350b72cc5b2c9 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ Official Starting Page: https://dotnet.microsoft.com/
We welcome contributions! Many people all over the world have helped make this project better.
-* [Contributing](CONTRIBUTING.md) explains what kinds of changes we welcome
+* [Contributing](CONTRIBUTING.md) explains what kinds of contributions we welcome
- [Workflow Instructions](docs/workflow/README.md) explains how to build and test
* [Get Up and Running on .NET Core](docs/project/dogfooding.md) explains how to get nightly builds of the runtime and its libraries to test them in your own projects.
diff --git a/docs/workflow/testing/mono/testing.md b/docs/workflow/testing/mono/testing.md
index 4c37f634de45c..8a03414e02a18 100644
--- a/docs/workflow/testing/mono/testing.md
+++ b/docs/workflow/testing/mono/testing.md
@@ -20,6 +20,10 @@ cd src/tests
./build.sh excludemonofailures
```
+To build an individual test, test directory, or a whole subdirectory tree, use the `-test:`, `-dir:` or `-tree:` options (without the src/tests prefix)
+For example: `./build.sh excludemonofailures release -test:JIT/opt/InstructionCombining/DivToMul.csproj`
+
+
Run individual test:
```
cd src/mono
@@ -32,6 +36,24 @@ cd src/mono
make run-tests-coreclr-all
```
+To debug a single test with `lldb`:
+
+1. Run the test at least once normally (or manually run the `mono.proj` `PatchCoreClrCoreRoot` target)
+2. Edit the `.sh` file for the test and change the line
+```
+ LAUNCHER="$_DebuggerFullPath "$CORE_ROOT/corerun" -p "System.Reflection.Metadata.MetadataUpdater.IsSupported=false" ${__DotEnvArg}"
+```
+to add `--` after the debugger full path
+```
+ LAUNCHER="$_DebuggerFullPath -- "$CORE_ROOT/corerun" -p "System.Reflection.Metadata.MetadataUpdater.IsSupported=false" ${__DotEnvArg}"
+```
+3. Run the shell script for the test case manually:
+```
+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
+```
+4. In LLDB add the debug symbols for mono: `add-dsym /libcoreclr.dylib.dwarf`
+5. Run/debug the test
+
### WebAssembly:
Build the runtime tests for WebAssembly
```
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 3fd61d12f163b..7638fc78f5901 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -72,7 +72,7 @@
host.native
packs.product
- $(DefaultPacksSubsets)+packs.tests
+ $(DefaultPacksSubsets)+packs.tests
$(DefaultPacksSubsets)+packs.installers
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 44b371499f890..ab38b44b996af 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,12 +1,12 @@
-
+
https://github.com/dotnet/icu
- 848e383f845cee4ab9edb8b20b40154910792599
+ ca9a6d29a62dd66925f5377d09b3d7e6afb2acd5
-
+
https://github.com/dotnet/msquic
- 9b90833648c8f4f24bb79f362562779667888068
+ feebeb23023b2806e5c6604e751b699fa8e83424
https://github.com/dotnet/emsdk
@@ -18,229 +18,229 @@
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
https://github.com/microsoft/vstest
140434f7109d357d0158ade9e5164a4861513965
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/llvm-project
- fadaad69ceb75cd54372336dde2193a39348e740
+ e20c0dbcf2fdc8979584b178cafd01db37121d64
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/runtime
- 78ac8430e8480742181170eef91a6fb016535aa4
+ 565ff522bf630ff0556f3dc590dcb7337696a5d4
-
+
https://github.com/dotnet/linker
- b0b20476551dacaf86946aeb957973a8540fb960
+ 0f1bca76ee6a360d67a624c12b5b8d427db66226
-
+
https://github.com/dotnet/xharness
- 27779945a6f28639f526ec3d1e02f76436c6d22d
+ 9eaf2814afcd7627059e5ea0ee2f5169a6409689
-
+
https://github.com/dotnet/xharness
- 27779945a6f28639f526ec3d1e02f76436c6d22d
+ 9eaf2814afcd7627059e5ea0ee2f5169a6409689
-
+
https://github.com/dotnet/arcade
- 3ea0d860c6973f2cbadc9e895c7ec2cbdaec4ad5
+ 9030d71b47f5a885a1f1d81ace8ec469249d88bc
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
- deb41ed73af3390e435a68fe6b5671f37113d526
+ a033eea960941a4aa1c2cd8084747a29535683ac
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
- deb41ed73af3390e435a68fe6b5671f37113d526
+ a033eea960941a4aa1c2cd8084747a29535683ac
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
- deb41ed73af3390e435a68fe6b5671f37113d526
+ a033eea960941a4aa1c2cd8084747a29535683ac
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
- deb41ed73af3390e435a68fe6b5671f37113d526
+ a033eea960941a4aa1c2cd8084747a29535683ac
-
+
https://github.com/dotnet/hotreload-utils
- fc3252e58fef2651652702298107f3fc3e3784cb
+ 1aa5a751a0c659c90f51b9d6b23c8cbd9d0a8dbb
-
+
https://github.com/dotnet/runtime-assets
- 426f10a0dcb1a9b5fa3bf5901f88bd3a54ccaa0a
+ f800c64524ca148d3a5e8e9204fcbc9cf5055148
-
+
https://github.com/dotnet/roslyn-analyzers
- 5e80ab913df6662e4c94b6bdaa443684706f8e52
+ ccd85bc350c9a994b74642f3b7613d8a98f5be2d
https://github.com/dotnet/sdk
diff --git a/eng/Versions.props b/eng/Versions.props
index 2649b6910290c..c33e0d6f64eec 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -51,36 +51,36 @@
3.3.2
4.0.0-4.final
4.0.0-4.final
- 7.0.0-preview1.21502.1
+ 7.0.0-preview1.21513.4
4.0.0-5.21453.15
1.0.0-rc.2.21501.51
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 2.5.1-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
- 7.0.0-beta.21474.2
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 2.5.1-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
+ 7.0.0-beta.21514.3
6.0.0-preview.1.102
- 7.0.0-alpha.1.21476.2
- 7.0.0-alpha.1.21476.2
- 7.0.0-alpha.1.21476.2
+ 7.0.0-alpha.1.21511.2
+ 7.0.0-alpha.1.21511.2
+ 7.0.0-alpha.1.21511.2
3.1.0
- 7.0.0-alpha.1.21476.2
+ 7.0.0-alpha.1.21511.2
5.0.0
4.3.0
@@ -114,28 +114,28 @@
5.0.0
5.0.0
4.9.0-rc2.21473.1
- 7.0.0-alpha.1.21476.2
- 7.0.0-alpha.1.21476.2
+ 7.0.0-alpha.1.21511.2
+ 7.0.0-alpha.1.21511.2
4.5.4
4.5.0
- 7.0.0-alpha.1.21476.2
+ 7.0.0-alpha.1.21511.2
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
- 7.0.0-beta.21479.3
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
+ 7.0.0-beta.21512.1
- 1.0.0-prerelease.21502.2
- 1.0.0-prerelease.21502.2
- 1.0.0-prerelease.21502.2
- 1.0.0-prerelease.21502.2
+ 1.0.0-prerelease.21514.8
+ 1.0.0-prerelease.21514.8
+ 1.0.0-prerelease.21514.8
+ 1.0.0-prerelease.21514.8
16.9.0-beta1.21055.5
2.0.0-beta1.20253.1
@@ -147,22 +147,16 @@
1.0.4-preview6.19326.1
0.2.61701
1.0.26
-
- 16.10.0
- $(RefOnlyMicrosoftBuildVersion)
- $(RefOnlyMicrosoftBuildVersion)
- $(RefOnlyMicrosoftBuildVersion)
- 5.8.0
- 5.8.0
+ 16.10.0
+ $(MicrosoftBuildVersion)
+ 5.8.0
+ 5.8.0
1.0.1-prerelease-00006
16.9.0-preview-20201201-01
- 1.0.0-prerelease.21501.2
- 1.0.0-prerelease.21501.2
- 1.0.2-alpha.0.21479.1
+ 1.0.0-prerelease.21511.3
+ 1.0.0-prerelease.21511.3
+ 1.0.2-alpha.0.21512.2
2.4.2-pre.9
2.4.2
1.3.0
@@ -175,21 +169,21 @@
6.0.0-preview-20210916.1
- 7.0.100-1.21504.4
+ 7.0.100-1.21513.1
$(MicrosoftNETILLinkTasksVersion)
- 7.0.0-alpha.1.21477.1
+ 7.0.0-alpha.1.21511.1
- 6.0.0-preview.7.21480.1
+ 6.0.0-preview.7.21514.2
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
- 11.1.0-alpha.1.21477.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
+ 11.1.0-alpha.1.21511.1
6.0.0-rc.1.21416.1
$(MicrosoftNETWorkloadEmscriptenManifest60100Version)
diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh
index 28f5145a6f794..8c944f30b2864 100644
--- a/eng/common/native/init-compiler.sh
+++ b/eng/common/native/init-compiler.sh
@@ -50,8 +50,8 @@ if [[ -z "$CLR_CC" ]]; then
# Set default versions
if [[ -z "$majorVersion" ]]; then
# note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero.
- if [[ "$compiler" == "clang" ]]; then versions=( 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 )
- elif [[ "$compiler" == "gcc" ]]; then versions=( 11 10 9 8 7 6 5 4.9 ); fi
+ if [[ "$compiler" == "clang" ]]; then versions=( 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 )
+ elif [[ "$compiler" == "gcc" ]]; then versions=( 12 11 10 9 8 7 6 5 4.9 ); fi
for version in "${versions[@]}"; do
parts=(${version//./ })
diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml
index cd02ae1607f3b..09a223989f7ec 100644
--- a/eng/common/templates/steps/send-to-helix.yml
+++ b/eng/common/templates/steps/send-to-helix.yml
@@ -20,7 +20,6 @@ parameters:
IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
- EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set
HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting int)
@@ -54,7 +53,6 @@ steps:
IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
- EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
@@ -85,7 +83,6 @@ steps:
IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
- EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake
index 3e819071f6111..a29857451bc79 100644
--- a/eng/native/configurecompiler.cmake
+++ b/eng/native/configurecompiler.cmake
@@ -367,6 +367,8 @@ if (CLR_CMAKE_HOST_UNIX)
#These seem to indicate real issues
add_compile_options($<$:-Wno-invalid-offsetof>)
+ add_compile_options(-Wno-unused-but-set-variable)
+
if (CMAKE_C_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-unknown-warning-option)
@@ -376,8 +378,6 @@ if (CLR_CMAKE_HOST_UNIX)
# Disabled warnings
add_compile_options(-Wno-unused-private-field)
- # Explicit constructor calls are not supported by clang (this->ClassName::ClassName())
- add_compile_options(-Wno-microsoft)
# There are constants of type BOOL used in a condition. But BOOL is defined as int
# and so the compiler thinks that there is a mistake.
add_compile_options(-Wno-constant-logical-operand)
@@ -390,8 +390,9 @@ if (CLR_CMAKE_HOST_UNIX)
# to a struct or a class that has virtual members or a base class. In that case, clang
# may not generate the same object layout as MSVC.
add_compile_options(-Wno-incompatible-ms-struct)
+
+ add_compile_options(-Wno-reserved-identifier)
else()
- add_compile_options(-Wno-unused-but-set-variable)
add_compile_options(-Wno-uninitialized)
add_compile_options(-Wno-strict-aliasing)
add_compile_options(-Wno-array-bounds)
diff --git a/eng/native/init-distro-rid.sh b/eng/native/init-distro-rid.sh
index eea8eca2d26d1..5f6b194600124 100644
--- a/eng/native/init-distro-rid.sh
+++ b/eng/native/init-distro-rid.sh
@@ -41,7 +41,7 @@ initNonPortableDistroRid()
# We have forced __PortableBuild=0. This is because -portablebuld
# has been passed as false.
if (( isPortable == 0 )); then
- if [ "${ID}" = "rhel" || "${ID}" = "rocky" ]; then
+ if [ "${ID}" = "rhel" ] || [ "${ID}" = "rocky" ]; then
# remove the last version digit
VERSION_ID="${VERSION_ID%.*}"
fi
diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml
index 3672691bbb05a..ff13637a92a14 100644
--- a/eng/pipelines/common/platform-matrix.yml
+++ b/eng/pipelines/common/platform-matrix.yml
@@ -209,6 +209,32 @@ jobs:
${{ insert }}: ${{ parameters.jobParameters }}
buildingOnSourceBuildImage: true
+# Linux s390x
+
+- ${{ if containsValue(parameters.platforms, 'Linux_s390x') }}:
+ - template: xplat-setup.yml
+ parameters:
+ jobTemplate: ${{ parameters.jobTemplate }}
+ helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }}
+ variables: ${{ parameters.variables }}
+ osGroup: Linux
+ archType: s390x
+ targetRid: linux-s390x
+ platform: Linux_s390x
+ container:
+ image: ubuntu-18.04-cross-s390x-20201102145728-d6e0352
+ registry: mcr
+ jobParameters:
+ runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ stagedBuild: ${{ parameters.stagedBuild }}
+ buildConfig: ${{ parameters.buildConfig }}
+ ${{ if eq(parameters.passPlatforms, true) }}:
+ platforms: ${{ parameters.platforms }}
+ helixQueueGroup: ${{ parameters.helixQueueGroup }}
+ crossBuild: true
+ crossrootfsDir: '/crossrootfs/s390x'
+ ${{ insert }}: ${{ parameters.jobParameters }}
+
# WebAssembly
- ${{ if containsValue(parameters.platforms, 'Browser_wasm') }}:
@@ -628,6 +654,33 @@ jobs:
helixQueueGroup: ${{ parameters.helixQueueGroup }}
${{ insert }}: ${{ parameters.jobParameters }}
+# Tizen armel
+
+- ${{ if containsValue(parameters.platforms, 'Tizen_armel') }}:
+ - template: xplat-setup.yml
+ parameters:
+ jobTemplate: ${{ parameters.jobTemplate }}
+ helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }}
+ variables: ${{ parameters.variables }}
+ osGroup: Tizen
+ archType: armel
+ targetRid: tizen-armel
+ platform: Tizen_armel
+ container:
+ image: ubuntu-18.04-cross-armel-tizen-20210719212651-8b02f56
+ registry: mcr
+ jobParameters:
+ runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ stagedBuild: ${{ parameters.stagedBuild }}
+ buildConfig: ${{ parameters.buildConfig }}
+ ${{ if eq(parameters.passPlatforms, true) }}:
+ platforms: ${{ parameters.platforms }}
+ helixQueueGroup: ${{ parameters.helixQueueGroup }}
+ crossBuild: true
+ crossrootfsDir: '/crossrootfs/armel'
+ disableClrTest: true
+ ${{ insert }}: ${{ parameters.jobParameters }}
+
# Windows x64
- ${{ if or(containsValue(parameters.platforms, 'windows_x64'), in(parameters.platformGroup, 'all', 'gcstress')) }}:
diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml
index 586a474175895..85a96ae5fce85 100644
--- a/eng/pipelines/common/xplat-setup.yml
+++ b/eng/pipelines/common/xplat-setup.yml
@@ -114,12 +114,12 @@ jobs:
${{ if eq(parameters.jobParameters.pool, '') }}:
pool:
# Public Linux Build Pool
- ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Android'), eq(parameters.hostedOs, 'Linux')), eq(variables['System.TeamProject'], 'public')) }}:
+ ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Android', 'Tizen'), eq(parameters.hostedOs, 'Linux')), eq(variables['System.TeamProject'], 'public')) }}:
name: NetCore1ESPool-Public
demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open
# Official Build Linux Pool
- ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Browser', 'Android'), eq(parameters.hostedOs, 'Linux')), ne(variables['System.TeamProject'], 'public')) }}:
+ ${{ if and(or(in(parameters.osGroup, 'Linux', 'FreeBSD', 'Browser', 'Android', 'Tizen'), eq(parameters.hostedOs, 'Linux')), ne(variables['System.TeamProject'], 'public')) }}:
name: NetCore1ESPool-Internal
demands: ImageOverride -equals Build.Ubuntu.1804.Amd64
diff --git a/eng/pipelines/coreclr/superpmi.yml b/eng/pipelines/coreclr/superpmi-collect.yml
similarity index 91%
rename from eng/pipelines/coreclr/superpmi.yml
rename to eng/pipelines/coreclr/superpmi-collect.yml
index d6325d87b74eb..7b285903a5fef 100644
--- a/eng/pipelines/coreclr/superpmi.yml
+++ b/eng/pipelines/coreclr/superpmi-collect.yml
@@ -58,7 +58,7 @@ jobs:
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-collect-job.yml
buildConfig: checked
platforms:
# Linux tests are built on the OSX machines.
@@ -79,7 +79,7 @@ jobs:
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-collect-job.yml
buildConfig: checked
platforms:
# Linux tests are built on the OSX machines.
@@ -101,7 +101,7 @@ jobs:
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-collect-job.yml
buildConfig: checked
platforms:
# Linux tests are built on the OSX machines.
@@ -123,7 +123,7 @@ jobs:
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-collect-job.yml
buildConfig: checked
platforms:
# Linux tests are built on the OSX machines.
@@ -144,7 +144,7 @@ jobs:
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/superpmi-job.yml
+ jobTemplate: /eng/pipelines/coreclr/templates/superpmi-collect-job.yml
buildConfig: checked
platforms:
# Linux tests are built on the OSX machines.
diff --git a/eng/pipelines/coreclr/superpmi-replay.yml b/eng/pipelines/coreclr/superpmi-replay.yml
index 83b4d2ac6237b..90ed1896c03af 100644
--- a/eng/pipelines/coreclr/superpmi-replay.yml
+++ b/eng/pipelines/coreclr/superpmi-replay.yml
@@ -8,10 +8,6 @@ trigger:
- src/coreclr/jit/*
- src/coreclr/inc/jiteeversionguid.h
-# This pipeline is supposed to be run only on merged changes
-# and should not be triggerable from a PR.
-pr: none
-
jobs:
- template: /eng/pipelines/common/platform-matrix.yml
diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml
index e94d630ba2e95..c5efb8c77bdd2 100644
--- a/eng/pipelines/coreclr/templates/build-job.yml
+++ b/eng/pipelines/coreclr/templates/build-job.yml
@@ -9,6 +9,7 @@ parameters:
crossBuild: false
crossrootfsDir: ''
dependOnEvaluatePaths: false
+ disableClrTest: false
isOfficialBuild: false
osGroup: ''
osSubgroup: ''
@@ -38,6 +39,7 @@ jobs:
pool: ${{ parameters.pool }}
condition: ${{ parameters.condition }}
dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths }}
+ disableClrTest: ${{ parameters.disableClrTest }}
pgoType: ${{ parameters.pgoType }}
# Compute job name from template parameters
@@ -141,6 +143,12 @@ jobs:
- name: SignType
value: $[ coalesce(variables.OfficialSignType, 'real') ]
+ - name: clrRuntimePortableBuildArg
+ value: ''
+ - ${{ if eq(parameters.archType, 'armel' )}}:
+ - name: clrRuntimePortableBuildArg
+ value: '-portablebuild=false'
+
- ${{ parameters.variables }}
steps:
@@ -188,7 +196,7 @@ jobs:
# Build CoreCLR Runtime
- ${{ if ne(parameters.osGroup, 'windows') }}:
- - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) $(osArg) -ci $(compilerArg) $(clrBuildPALTestsBuildArg) $(pgoInstrumentArg) $(officialBuildIdArg) $(clrInterpreterBuildArg)
+ - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) $(osArg) -ci $(compilerArg) $(clrBuildPALTestsBuildArg) $(pgoInstrumentArg) $(officialBuildIdArg) $(clrInterpreterBuildArg) $(clrRuntimePortableBuildArg)
displayName: Build CoreCLR Runtime
- ${{ if eq(parameters.osGroup, 'windows') }}:
- script: set __TestIntermediateDir=int&&$(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) -ci $(enforcePgoArg) $(pgoInstrumentArg) $(officialBuildIdArg) $(clrInterpreterBuildArg)
@@ -210,7 +218,7 @@ jobs:
displayName: Run CoreCLR Tools unit tests
# Build native test components
- - ${{ if ne(parameters.isOfficialBuild, true) }}:
+ - ${{ if and(ne(parameters.isOfficialBuild, true), ne(parameters.disableClrTest, true)) }}:
- script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) skipmanaged skipgeneratelayout $(buildConfig) $(archType) $(crossArg) $(osArg) $(priorityArg) $(compilerArg)
displayName: Build native test components
@@ -257,7 +265,7 @@ jobs:
condition: always()
# Builds using gcc are not tested, and clrTools unitests do not publish the build artifacts
- - ${{ if and(ne(parameters.compilerName, 'gcc'), ne(parameters.testGroup, 'clrTools')) }}:
+ - ${{ if and(ne(parameters.compilerName, 'gcc'), ne(parameters.testGroup, 'clrTools'), ne(parameters.disableClrTest, true)) }}:
# Publish product output directory for consumption by tests.
- template: /eng/pipelines/common/upload-artifact-step.yml
parameters:
@@ -276,7 +284,7 @@ jobs:
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
- - ${{ if and(ne(parameters.compilerName, 'gcc'), ne(parameters.testGroup, ''), ne(parameters.testGroup, 'clrTools')) }}:
+ - ${{ if and(ne(parameters.compilerName, 'gcc'), ne(parameters.testGroup, ''), ne(parameters.testGroup, 'clrTools'), ne(parameters.disableClrTest, true)) }}:
# Publish test native components for consumption by test execution.
- ${{ if and(ne(parameters.isOfficialBuild, true), eq(parameters.pgoType, '')) }}:
- template: /eng/pipelines/common/upload-artifact-step.yml
diff --git a/eng/pipelines/coreclr/templates/jit-exploratory-job.yml b/eng/pipelines/coreclr/templates/jit-exploratory-job.yml
index 5992b1088bd0d..b3e1e9d089e56 100644
--- a/eng/pipelines/coreclr/templates/jit-exploratory-job.yml
+++ b/eng/pipelines/coreclr/templates/jit-exploratory-job.yml
@@ -3,7 +3,6 @@ parameters:
archType: ''
osGroup: ''
osSubgroup: ''
- container: ''
runtimeVariant: ''
testGroup: ''
framework: net6.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0)
@@ -13,8 +12,6 @@ parameters:
runtimeType: 'coreclr'
pool: ''
codeGenType: 'JIT'
- projetFile: ''
- runKind: ''
runJobTemplate: '/eng/pipelines/coreclr/templates/jit-run-exploratory-job.yml'
additionalSetupParameters: ''
@@ -27,8 +24,8 @@ jobs:
- template: ${{ parameters.runJobTemplate }}
parameters:
# Compute job name from template parameters
- jobName: ${{ format('exploratory_{0}{1}_{2}_{3}_{4}_{5}_{6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType, parameters.runKind) }}
- displayName: ${{ format('Exploratory {0}{1} {2} {3} {4} {5} {6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType, parameters.runKind) }}
+ jobName: ${{ format('exploratory_{0}{1}_{2}_{3}_{4}_{5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType) }}
+ displayName: ${{ format('Exploratory {0}{1} {2} {3} {4} {5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType) }}
pool: ${{ parameters.pool }}
buildConfig: ${{ parameters.buildConfig }}
archType: ${{ parameters.archType }}
@@ -38,7 +35,6 @@ jobs:
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
runtimeType: ${{ parameters.runtimeType }}
codeGenType: ${{ parameters.codeGenType }}
- runKind: ${{ parameters.runKind }}
testGroup: ${{ parameters.testGroup }}
helixQueues: ${{ parameters.helixQueues }}
additionalSetupParameters: ${{ parameters.additionalSetupParameters }}
diff --git a/eng/pipelines/coreclr/templates/jit-run-exploratory-job.yml b/eng/pipelines/coreclr/templates/jit-run-exploratory-job.yml
index 427bba150c812..3c0dbbbfea3fc 100644
--- a/eng/pipelines/coreclr/templates/jit-run-exploratory-job.yml
+++ b/eng/pipelines/coreclr/templates/jit-run-exploratory-job.yml
@@ -9,8 +9,6 @@ parameters:
archType: '' # required -- targeting CPU architecture
osGroup: '' # required -- operating system for the job
osSubgroup: '' # optional -- operating system subgroup
- extraSetupParameters: '' # optional -- extra arguments to pass to the setup script
- frameworks: ['net6.0'] # optional -- list of frameworks to run against
continueOnError: 'false' # optional -- determines whether to continue the build if the step errors
dependsOn: '' # optional -- dependencies of the job
timeoutInMinutes: 320 # optional -- timeout for the job
@@ -18,8 +16,7 @@ parameters:
liveLibrariesBuildConfig: '' # optional -- live-live libraries configuration to use for the run
runtimeType: 'coreclr' # optional -- Sets the runtime as coreclr or mono
codeGenType: 'JIT' # optional -- Decides on the codegen technology if running on mono
- runKind: '' # required -- test category
- helixQueues: '' # required -- Helix queue
+ helixQueues: '' # required -- Helix queues
dependOnEvaluatePaths: false
jobs:
@@ -54,6 +51,12 @@ jobs:
- HelixApiAccessToken: ''
- HelixPreCommand: ''
+ - ${{ if in(variables['Build.Reason'], 'Schedule') }}:
+ - name: RunReason
+ value: 'Scheduled'
+ - ${{ if notin(variables['Build.Reason'], 'Schedule') }}:
+ - name: RunReason
+ value: 'PR'
- ${{ if eq(parameters.osGroup, 'windows') }}:
- name: PythonScript
value: 'py -3'
@@ -65,6 +68,8 @@ jobs:
value: '$(Build.SourcesDirectory)\artifacts\helixresults\'
- name: IssuesSummaryLocation
value: '$(Build.SourcesDirectory)\artifacts\issues_summary\'
+ - name: AntigenLogsLocation
+ value: '$(Build.SourcesDirectory)\artifacts\antigen_logs\'
- ${{ if ne(parameters.osGroup, 'windows') }}:
- name: PythonScript
@@ -77,16 +82,14 @@ jobs:
value: '$(Build.SourcesDirectory)/artifacts/helixresults/'
- name: IssuesSummaryLocation
value: '$(Build.SourcesDirectory)/artifacts/issues_summary/'
+ - name: AntigenLogsLocation
+ value: '$(Build.SourcesDirectory)/artifacts/antigen_logs/'
+
workspace:
clean: all
pool:
${{ parameters.pool }}
container: ${{ parameters.container }}
- strategy:
- matrix:
- ${{ each framework in parameters.frameworks }}:
- ${{ framework }}:
- _Framework: ${{ framework }}
steps:
- ${{ parameters.steps }}
@@ -110,6 +113,7 @@ jobs:
osGroup: ${{ parameters.osGroup }}
RunConfiguration: '$(RunConfiguration)'
ToolName: '$(ToolName)'
+ RunReason: '$(RunReason)'
continueOnError: true
- template: /eng/pipelines/common/upload-artifact-step.yml
@@ -129,20 +133,43 @@ jobs:
sourceFolder: '$(IssuesLocation)'
contents: '**/issues-summary-*.txt'
targetFolder: '$(IssuesSummaryLocation)'
+ continueOnError: true
+ condition: always()
- task: PublishPipelineArtifact@1
displayName: Publish issues-summary.txt files
inputs:
targetPath: $(IssuesSummaryLocation)
artifactName: 'Issues_Summary_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ continueOnError: true
+ condition: always()
+
+ # Always upload the available Antigen.log files
+ - task: CopyFiles@2
+ displayName: Copying Antigen.logs of all partitions
+ inputs:
+ sourceFolder: '$(IssuesLocation)'
+ contents: '**/Antigen-*.log'
+ targetFolder: '$(AntigenLogsLocation)'
+ continueOnError: true
+ condition: always()
+
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Antigen.log files
+ inputs:
+ targetPath: $(AntigenLogsLocation)
+ artifactName: 'Antigen_Logs_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ continueOnError: true
+ condition: always()
- script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/antigen_unique_issues.py -issues_directory $(IssuesSummaryLocation)
displayName: ${{ format('Print unique issues ({0})', parameters.osGroup) }}
continueOnError: true
+ condition: always()
- task: PublishPipelineArtifact@1
displayName: Publish Antigen build logs
inputs:
targetPath: $(Build.SourcesDirectory)/artifacts/log
- artifactName: 'Antigen_BuildLogs__$(archType)_$(buildConfig)'
+ artifactName: 'Antigen_BuildLogs_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
condition: always()
\ No newline at end of file
diff --git a/eng/pipelines/coreclr/templates/run-superpmi-job.yml b/eng/pipelines/coreclr/templates/run-superpmi-collect-job.yml
similarity index 87%
rename from eng/pipelines/coreclr/templates/run-superpmi-job.yml
rename to eng/pipelines/coreclr/templates/run-superpmi-collect-job.yml
index 78a4e778c733f..01726c6b1a339 100644
--- a/eng/pipelines/coreclr/templates/run-superpmi-job.yml
+++ b/eng/pipelines/coreclr/templates/run-superpmi-collect-job.yml
@@ -9,16 +9,11 @@ parameters:
archType: '' # required -- targeting CPU architecture
osGroup: '' # required -- operating system for the job
osSubgroup: '' # optional -- operating system subgroup
- extraSetupParameters: '' # optional -- extra arguments to pass to the setup script
- frameworks: ['netcoreapp3.0'] # optional -- list of frameworks to run against
continueOnError: 'false' # optional -- determines whether to continue the build if the step errors
dependsOn: '' # optional -- dependencies of the job
timeoutInMinutes: 320 # optional -- timeout for the job
enableTelemetry: false # optional -- enable for telemetry
liveLibrariesBuildConfig: '' # optional -- live-live libraries configuration to use for the run
- runtimeType: 'coreclr' # optional -- Sets the runtime as coreclr or mono
- codeGenType: 'JIT' # optional -- Decides on the codegen technology if running on mono
- runKind: '' # required -- test category
collectionType: ''
collectionName: ''
dependOnEvaluatePaths: false
@@ -108,15 +103,10 @@ jobs:
pool:
${{ parameters.pool }}
container: ${{ parameters.container }}
- strategy:
- matrix:
- ${{ each framework in parameters.frameworks }}:
- ${{ framework }}:
- _Framework: ${{ framework }}
steps:
- ${{ parameters.steps }}
- - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi_setup.py -source_directory $(Build.SourcesDirectory) -core_root_directory $(Core_Root_Dir) -arch $(archType) -mch_file_tag $(MchFileTag) -input_directory $(InputDirectory) -collection_name $(CollectionName) -collection_type $(CollectionType) -max_size 50 # size in MB
+ - script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi_collect_setup.py -source_directory $(Build.SourcesDirectory) -core_root_directory $(Core_Root_Dir) -arch $(archType) -mch_file_tag $(MchFileTag) -input_directory $(InputDirectory) -collection_name $(CollectionName) -collection_type $(CollectionType) -max_size 50 # size in MB
displayName: ${{ format('SuperPMI setup ({0})', parameters.osGroup) }}
# Create required directories for merged mch collection and superpmi logs
@@ -135,7 +125,7 @@ jobs:
- template: /eng/pipelines/coreclr/templates/superpmi-send-to-helix.yml
parameters:
HelixSource: '$(HelixSourcePrefix)/$(Build.Repository.Name)/$(Build.SourceBranch)' # sources must start with pr/, official/, prodcon/, or agent/
- HelixType: 'test/superpmi/$(CollectionName)/$(CollectionType)/$(_Framework)/$(Architecture)'
+ HelixType: 'test/superpmi/$(CollectionName)/$(CollectionType)/$(Architecture)'
HelixAccessToken: $(HelixApiAccessToken)
HelixTargetQueues: $(Queue)
HelixPreCommands: $(HelixPreCommand)
@@ -143,7 +133,7 @@ jobs:
WorkItemTimeout: 4:00 # 4 hours
WorkItemDirectory: '$(WorkItemDirectory)'
CorrelationPayloadDirectory: '$(CorrelationPayloadDirectory)'
- ProjectFile: 'superpmi.proj'
+ ProjectFile: 'superpmi-collect.proj'
BuildConfig: ${{ parameters.buildConfig }}
osGroup: ${{ parameters.osGroup }}
InputArtifacts: '$(InputArtifacts)'
@@ -151,7 +141,7 @@ jobs:
CollectionName: '$(CollectionName)'
continueOnError: true # Run the future step i.e. merge-mch step even if this step fails.
- # Always run merged step even if collection of some partition fails so we can store collection
+ # Always run merge step even if collection of some partition fails so we can store collection
# of the partitions that succeeded. If all the partitions fail, merge-mch would fail and we won't
# run future steps like uploading superpmi collection.
- script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi.py merge-mch -log_level DEBUG -pattern $(MchFilesLocation)$(CollectionName).$(CollectionType)*.mch -output_mch_path $(MergedMchFileLocation)$(CollectionName).$(CollectionType).$(MchFileTag).mch
@@ -166,7 +156,7 @@ jobs:
archiveType: $(archiveType)
tarCompression: $(tarCompression)
archiveExtension: $(archiveExtension)
- artifactName: 'SuperPMI_Collection_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.runtimeType }}_${{ parameters.codeGenType }}_${{ parameters.runKind }}'
+ artifactName: 'SuperPMI_Collection_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
displayName: ${{ format('Upload artifacts SuperPMI {0}-{1} collection', parameters.collectionName, parameters.collectionType) }}
- script: $(PythonScript) $(Build.SourcesDirectory)/src/coreclr/scripts/superpmi.py upload -log_level DEBUG -arch $(archType) -build_type $(buildConfig) -mch_files $(MergedMchFileLocation)$(CollectionName).$(CollectionType).$(MchFileTag).mch -core_root $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).x64.$(buildConfigUpper)
@@ -184,15 +174,15 @@ jobs:
condition: always()
- task: PublishPipelineArtifact@1
- displayName: Publish Superpmi logs
+ displayName: Publish SuperPMI logs
inputs:
targetPath: $(SpmiLogsLocation)
- artifactName: 'SuperPMI_Logs_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.runtimeType }}_${{ parameters.codeGenType }}_${{ parameters.runKind }}'
+ artifactName: 'SuperPMI_Logs_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
condition: always()
- task: PublishPipelineArtifact@1
displayName: Publish SuperPMI build logs
inputs:
targetPath: $(Build.SourcesDirectory)/artifacts/log
- artifactName: 'SuperPMI_BuildLogs_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.runtimeType }}_${{ parameters.codeGenType }}_${{ parameters.runKind }}'
+ artifactName: 'SuperPMI_BuildLogs_$(CollectionName)_$(CollectionType)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
condition: always()
diff --git a/eng/pipelines/coreclr/templates/run-superpmi-replay-job.yml b/eng/pipelines/coreclr/templates/run-superpmi-replay-job.yml
index f267329a86760..979d0912388bc 100644
--- a/eng/pipelines/coreclr/templates/run-superpmi-replay-job.yml
+++ b/eng/pipelines/coreclr/templates/run-superpmi-replay-job.yml
@@ -9,18 +9,12 @@ parameters:
archType: '' # required -- targeting CPU architecture
osGroup: '' # required -- operating system for the job
osSubgroup: '' # optional -- operating system subgroup
- extraSetupParameters: '' # optional -- extra arguments to pass to the setup script
- frameworks: ['netcoreapp3.0'] # optional -- list of frameworks to run against
continueOnError: 'false' # optional -- determines whether to continue the build if the step errors
dependsOn: '' # optional -- dependencies of the job
timeoutInMinutes: 320 # optional -- timeout for the job
enableTelemetry: false # optional -- enable for telemetry
liveLibrariesBuildConfig: '' # optional -- live-live libraries configuration to use for the run
- runtimeType: 'coreclr' # optional -- Sets the runtime as coreclr or mono
- codeGenType: 'JIT' # optional -- Decides on the codegen technology if running on mono
- runKind: '' # required -- test category
- collectionType: ''
- collectionName: ''
+ helixQueues: '' # required -- Helix queues
dependOnEvaluatePaths: false
jobs:
@@ -35,8 +29,6 @@ jobs:
enableTelemetry: ${{ parameters.enableTelemetry }}
enablePublishBuildArtifacts: true
continueOnError: ${{ parameters.continueOnError }}
- collectionType: $ {{ parameters.collectionType }}
- collectionName: ${{ parameters.collectionName }}
dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
@@ -46,6 +38,7 @@ jobs:
displayName: '${{ parameters.jobName }}'
variables:
+
- ${{ each variable in parameters.variables }}:
- ${{ if ne(variable.name, '') }}:
- name: ${{ variable.name }}
@@ -69,11 +62,6 @@ jobs:
pool:
${{ parameters.pool }}
container: ${{ parameters.container }}
- strategy:
- matrix:
- ${{ each framework in parameters.frameworks }}:
- ${{ framework }}:
- _Framework: ${{ framework }}
steps:
- ${{ parameters.steps }}
@@ -85,17 +73,18 @@ jobs:
displayName: ${{ format('SuperPMI replay setup ({0} {1})', parameters.osGroup, parameters.archType) }}
# Run superpmi replay in helix
- - template: /eng/pipelines/coreclr/templates/superpmi-send-to-helix.yml
+ - template: /eng/pipelines/common/templates/runtimes/send-to-helix-step.yml
parameters:
- HelixSource: '$(HelixSourcePrefix)/$(Build.Repository.Name)/$(Build.SourceBranch)' # sources must start with pr/, official/, prodcon/, or agent/
- HelixAccessToken: $(HelixApiAccessToken)
- HelixTargetQueues: $(Queue)
- HelixPreCommands: $(HelixPreCommand)
- Creator: $(Creator)
+ displayName: 'Send job to Helix'
+ helixBuild: $(Build.BuildNumber)
+ helixSource: $(_HelixSource)
+ helixType: 'build/tests/'
+ helixQueues: ${{ join(',', parameters.helixQueues) }}
+ creator: dotnet-bot
WorkItemTimeout: 4:00 # 4 hours
WorkItemDirectory: '$(WorkItemDirectory)'
CorrelationPayloadDirectory: '$(CorrelationPayloadDirectory)'
- ProjectFile: 'superpmi-replay.proj'
+ helixProjectArguments: '$(Build.SourcesDirectory)/src/coreclr/scripts/superpmi-replay.proj'
BuildConfig: ${{ parameters.buildConfig }}
osGroup: ${{ parameters.osGroup }}
archType: ${{ parameters.archType }}
@@ -111,7 +100,7 @@ jobs:
condition: always()
- task: PublishPipelineArtifact@1
- displayName: Publish Superpmi logs
+ displayName: Publish SuperPMI logs
inputs:
targetPath: $(SpmiLogsLocation)
artifactName: 'SuperPMI_Logs_$(archType)_$(buildConfig)'
@@ -121,5 +110,5 @@ jobs:
displayName: Publish SuperPMI build logs
inputs:
targetPath: $(Build.SourcesDirectory)/artifacts/log
- artifactName: 'SuperPMI_BuildLogs__$(archType)_$(buildConfig)'
- condition: always()
\ No newline at end of file
+ artifactName: 'SuperPMI_BuildLogs_$(archType)_$(buildConfig)'
+ condition: always()
diff --git a/eng/pipelines/coreclr/templates/superpmi-job.yml b/eng/pipelines/coreclr/templates/superpmi-collect-job.yml
similarity index 69%
rename from eng/pipelines/coreclr/templates/superpmi-job.yml
rename to eng/pipelines/coreclr/templates/superpmi-collect-job.yml
index c51ca723c9e60..6c990a25ff4aa 100644
--- a/eng/pipelines/coreclr/templates/superpmi-job.yml
+++ b/eng/pipelines/coreclr/templates/superpmi-collect-job.yml
@@ -3,62 +3,43 @@ parameters:
archType: ''
osGroup: ''
osSubgroup: ''
- container: ''
- runtimeVariant: ''
- testGroup: ''
- framework: net5.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0)
liveLibrariesBuildConfig: ''
variables: {}
- runtimeType: 'coreclr'
pool: ''
- codeGenType: 'JIT'
- projetFile: ''
- runKind: ''
- runJobTemplate: '/eng/pipelines/coreclr/templates/run-superpmi-job.yml'
- additionalSetupParameters: ''
+ runJobTemplate: '/eng/pipelines/coreclr/templates/run-superpmi-collect-job.yml'
collectionType: ''
collectionName: ''
### SuperPMI job
-
-### Each superpmi job depends on a corresponding build job with the same
-### buildConfig and archType.
+### Each collection job depends on a corresponding build job with the same buildConfig and archType.
jobs:
- template: ${{ parameters.runJobTemplate }}
parameters:
# Compute job name from template parameters
- jobName: ${{ format('superpmibuild_{0}{1}_{2}_{3}_{4}_{5}_{6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType, parameters.runKind) }}
- displayName: ${{ format('SuperPMI {7} {8} {0}{1} {2} {3} {4} {5} {6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType, parameters.codeGenType, parameters.runKind, parameters.collectionName, parameters.collectionType) }}
+ jobName: ${{ format('superpmi_collect_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ displayName: ${{ format('SuperPMI collect {4} {5} {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.collectionName, parameters.collectionType) }}
pool: ${{ parameters.pool }}
buildConfig: ${{ parameters.buildConfig }}
archType: ${{ parameters.archType }}
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
- runtimeVariant: ${{ parameters.runtimeVariant }}
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
- runtimeType: ${{ parameters.runtimeType }}
- codeGenType: ${{ parameters.codeGenType }}
- runKind: ${{ parameters.runKind }}
- testGroup: ${{ parameters.testGroup }}
collectionType: ${{ parameters.collectionType }}
collectionName: ${{ parameters.collectionName }}
- additionalSetupParameters: ${{ parameters.additionalSetupParameters }}
# Test job depends on the corresponding build job
dependsOn:
- - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ - ${{ format('coreclr__product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
# Depend on coreclr x64 so we can download it and use mcs.exe from it while publishing non-x64 arch SPMI collection
- ${{ if ne(parameters.archType, 'x64') }}:
- - ${{ format('coreclr_{0}_product_build_{1}{2}_x64_{3}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.buildConfig) }}
+ - ${{ format('coreclr__product_build_{0}{1}_x64_{2}', parameters.osGroup, parameters.osSubgroup, parameters.buildConfig) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
- ${{ if eq(parameters.collectionName, 'coreclr_tests') }}:
- - '${{ parameters.runtimeType }}_common_test_build_p1_AnyOS_AnyCPU_${{parameters.buildConfig }}'
+ - 'coreclr_common_test_build_p1_AnyOS_AnyCPU_${{parameters.buildConfig }}'
variables: ${{ parameters.variables }}
- frameworks:
- - ${{ parameters.framework }}
steps:
# Extra steps that will be passed to the superpmi template and run before sending the job to helix (all of which is done in the template)
@@ -85,8 +66,8 @@ jobs:
- template: /eng/pipelines/common/download-artifact-step.yml
parameters:
unpackFolder: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).x64.$(buildConfigUpper)'
- artifactFileName: 'CoreCLRProduct__${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_x64_$(buildConfig)$(archiveExtension)'
- artifactName: 'CoreCLRProduct__${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_x64_$(buildConfig)'
+ artifactFileName: 'CoreCLRProduct___$(osGroup)$(osSubgroup)_x64_$(buildConfig)$(archiveExtension)'
+ artifactName: 'CoreCLRProduct___$(osGroup)$(osSubgroup)_x64_$(buildConfig)'
displayName: 'Coreclr product build (x64)'
# Download and unzip managed test artifacts
diff --git a/eng/pipelines/coreclr/templates/superpmi-replay-job.yml b/eng/pipelines/coreclr/templates/superpmi-replay-job.yml
index ab481ee6a78f3..c0aac714341fd 100644
--- a/eng/pipelines/coreclr/templates/superpmi-replay-job.yml
+++ b/eng/pipelines/coreclr/templates/superpmi-replay-job.yml
@@ -4,18 +4,17 @@ parameters:
osGroup: '' # required -- operating system for the job
osSubgroup: '' # optional -- operating system subgroup
pool: ''
- stagedBuild: false
timeoutInMinutes: 320 # build timeout
- framework: net5.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0)
variables: {}
+ helixQueues: ''
dependOnEvaluatePaths: false
runJobTemplate: '/eng/pipelines/coreclr/templates/run-superpmi-replay-job.yml'
jobs:
- template: ${{ parameters.runJobTemplate }}
parameters:
- jobName: ${{ format('superpmibuild_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('SuperPMI replay {0} {1}', parameters.osGroup, parameters.archType) }}
+ jobName: ${{ format('superpmi_replay_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ displayName: ${{ format('SuperPMI replay {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
pool: ${{ parameters.pool }}
buildConfig: ${{ parameters.buildConfig }}
archType: ${{ parameters.archType }}
@@ -23,15 +22,12 @@ jobs:
osSubgroup: ${{ parameters.osSubgroup }}
dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
- additionalSetupParameters: ${{ parameters.additionalSetupParameters }}
+ helixQueues: ${{ parameters.helixQueues }}
dependsOn:
- ${{ format('coreclr_jit_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
variables: ${{ parameters.variables }}
- frameworks:
- - ${{ parameters.framework }}
-
steps:
# Download jit builds
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index 5a82951839ff4..73432c9c408b1 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -82,6 +82,10 @@ jobs:
# Limiting interp runs as we don't need as much coverage.
- (Debian.10.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-20210304164434-56c6673
+ # Linux s390x
+ - ${{ if eq(parameters.platform, 'Linux_s390x') }}:
+ - Ubuntu.2004.S390X.Experimental.Open
+
# OSX arm64
- ${{ if eq(parameters.platform, 'OSX_arm64') }}:
- OSX.1100.ARM64.Open
diff --git a/eng/pipelines/runtime-community.yml b/eng/pipelines/runtime-community.yml
new file mode 100644
index 0000000000000..5bebcc00a2663
--- /dev/null
+++ b/eng/pipelines/runtime-community.yml
@@ -0,0 +1,59 @@
+trigger: none
+
+schedules:
+ - cron: "0 7,19 * * *" # run at 7:00 and 19:00 (UTC) which is 23:00 and 11:00 (PST).
+ displayName: Runtime-community default schedule
+ branches:
+ include:
+ - main
+ always: false # run only if there were changes since the last successful scheduled run.
+
+variables:
+ - template: /eng/pipelines/common/variables.yml
+
+jobs:
+#
+# Evaluate paths
+#
+- ${{ if eq(variables.dependOnEvaluatePaths, true) }}:
+ - template: /eng/pipelines/common/evaluate-default-paths.yml
+
+#
+# s390x
+# Build the whole product using Mono and run libraries tests
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ runtimeFlavor: mono
+ platforms:
+ - Linux_s390x
+ variables:
+ # map dependencies variables to local variables
+ - name: librariesContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
+ - name: monoContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: AllSubsets_Mono
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true
+ 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)
+ condition: >-
+ or(
+ eq(variables['librariesContainsChange'], true),
+ eq(variables['monoContainsChange'], true),
+ eq(variables['isFullMatrix'], true))
diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml
index 580c695a01319..49fd3cdecb98d 100644
--- a/eng/pipelines/runtime-staging.yml
+++ b/eng/pipelines/runtime-staging.yml
@@ -1,3 +1,27 @@
+# Setting batch to true, triggers one build at a time.
+# if there is a push while a build in progress, it will wait,
+# until the running build finishes, and produce a build with all the changes
+# that happened during the last build.
+trigger:
+ batch: true
+ branches:
+ include:
+ - release/*.*
+ paths:
+ include:
+ - '*'
+ exclude:
+ - eng/Version.Details.xml
+ - .github/*
+ - docs/*
+ - CODE-OF-CONDUCT.md
+ - CONTRIBUTING.md
+ - LICENSE.TXT
+ - PATENTS.TXT
+ - README.md
+ - SECURITY.md
+ - THIRD-PARTY-NOTICES.TXT
+
schedules:
- cron: "0 7,19 * * *" # run at 7:00 and 19:00 (UTC) which is 23:00 and 11:00 (PST).
displayName: Runtime-staging default schedule
@@ -160,7 +184,6 @@ jobs:
extraStepsTemplate: /eng/pipelines/libraries/helix.yml
extraStepsParameters:
creator: dotnet-bot
- interpreter: true
testRunNamePrefixSuffix: Mono_$(_BuildConfig)
condition: >-
or(
@@ -401,12 +424,13 @@ jobs:
eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
eq(variables['isFullMatrix'], true))
# don't run tests on PRs until we can get significantly more devices
- ${{ if eq(variables['isFullMatrix'], true) }}:
- # extra steps, run tests
- extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml
- extraStepsParameters:
- creator: dotnet-bot
- testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ # Turn off the testing for now, until https://github.com/dotnet/xharness/issues/663 gets resolved
+ # ${{ if eq(variables['isFullMatrix'], true) }}:
+ # # extra steps, run tests
+ # extraStepsTemplate: /eng/pipelines/common/templates/runtimes/android-runtime-and-send-to-helix.yml
+ # extraStepsParameters:
+ # creator: dotnet-bot
+ # testRunNamePrefixSuffix: Mono_$(_BuildConfig)
# Run disabled installer tests on Linux x64
- template: /eng/pipelines/common/platform-matrix.yml
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index ddeca884f3229..b18a7ae71393b 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -79,6 +79,7 @@ jobs:
- Linux_musl_arm64
- Linux_musl_x64
- OSX_arm64
+ - Tizen_armel
- windows_x86
- windows_x64
- windows_arm
diff --git a/eng/testing/performance/blazor_perf.proj b/eng/testing/performance/blazor_perf.proj
index 000bcaa43fecd..144de9f06aed2 100644
--- a/eng/testing/performance/blazor_perf.proj
+++ b/eng/testing/performance/blazor_perf.proj
@@ -39,13 +39,13 @@
$(WorkItemDirectory)
- cd $(BlazorMinDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true%3B/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions="%24(AdditionalMonoLinkerOptions) --dump-dependencies"
+ cd $(BlazorMinDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true;;/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions="%24(AdditionalMonoLinkerOptions) --dump-dependencies"
$(Python) test.py sod --scenario-name "%(Identity)"
$(WorkItemDirectory)
- cd $(BlazorMinAOTDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true%3B/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions="%24(AdditionalMonoLinkerOptions) --dump-dependencies"
+ cd $(BlazorMinAOTDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true;;/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions="%24(AdditionalMonoLinkerOptions) --dump-dependencies"
$(Python) test.py sod --scenario-name "%(Identity)"
@@ -56,7 +56,7 @@
$(WorkItemDirectory)
- cd $(BlazorAOTDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true%3B/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions=%27"%24(AdditionalMonoLinkerOptions) --dump-dependencies"%27 --binlog %27./traces/blazor_publish.binlog%27
+ cd $(BlazorAOTDirectory);$(Python) pre.py publish --msbuild "/p:_TrimmerDumpDependencies=true;;/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions=%27"%24(AdditionalMonoLinkerOptions) --dump-dependencies"%27 --binlog %27./traces/blazor_publish.binlog%27
$(Python) test.py sod --scenario-name "%(Identity)"
$(Python) post.py
@@ -70,7 +70,7 @@
$(WorkItemDirectory)
- cd $(BlazorPizzaAOTDirectory);$(Python) pre.py publish -f $(PerflabTargetFrameworks) --msbuild "/p:_TrimmerDumpDependencies=true%3B/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions=%27"%24(AdditionalMonoLinkerOptions) --dump-dependencies"%27 --binlog %27./traces/blazor_publish.binlog%27
+ cd $(BlazorPizzaAOTDirectory);$(Python) pre.py publish -f $(PerflabTargetFrameworks) --msbuild "/p:_TrimmerDumpDependencies=true;;/p:_MonoRuntimeComponentManifestJsonFilePath=$(WASMRuntimeConfigPath)" --msbuild-static AdditionalMonoLinkerOptions=%27"%24(AdditionalMonoLinkerOptions) --dump-dependencies"%27 --binlog %27./traces/blazor_publish.binlog%27
$(Python) test.py sod --scenario-name "%(Identity)" --dirs $(PizzaAppPubLocation)
$(Python) post.py
1:00
diff --git a/eng/testing/performance/performance-setup.ps1 b/eng/testing/performance/performance-setup.ps1
index b4db23932ce34..ae30e9bac80ea 100644
--- a/eng/testing/performance/performance-setup.ps1
+++ b/eng/testing/performance/performance-setup.ps1
@@ -28,51 +28,6 @@ Param(
[switch] $iOSLlvmBuild
)
-function Verified-Move-Item {
- [CmdletBinding()]
- param(
- [Parameter(mandatory=$true)]
- [string]$Path,
- [Parameter(mandatory=$true)]
- [string]$Destination
- )
-
- Move-Item -Path $Path -Destination $Destination
- if (!$?) {
- Write-Output "Failed to move $Path to $Destination"
- exit 1
- }
-}
-
-function Verified-Copy-Item {
- [CmdletBinding()]
- param(
- [Parameter(mandatory=$true)]
- [string]$Path,
- [Parameter(mandatory=$true)]
- [string]$Destination
- )
-
- Copy-Item -path $Path $Destination
- if (!$?) {
- Write-Output "Failed to copy $Path to $Destination"
- exit 1
- }
-}
-
-function Verify-Robocopy {
- [CmdletBinding()]
- param(
- [Parameter(mandatory=$true)]
- [string]$Source
- )
-
- if ($LASTEXITCODE -ne 0 -or !$?) {
- Write-Output "Failed to copy ${Source}: exit code $LASTEXITCODE"
- exit $LASTEXITCODE
- }
-}
-
$RunFromPerformanceRepo = ($Repository -eq "dotnet/performance") -or ($Repository -eq "dotnet-performance")
$UseCoreRun = ($CoreRootDirectory -ne [string]::Empty)
$UseBaselineCoreRun = ($BaselineCoreRootDirectory -ne [string]::Empty)
@@ -167,30 +122,25 @@ if ($RunFromPerformanceRepo) {
$SetupArguments = "--perf-hash $CommitSha $CommonSetupArguments"
robocopy $SourceDirectory $PerformanceDirectory /E /XD $PayloadDirectory $SourceDirectory\artifacts $SourceDirectory\.git
- Verify-Robocopy $SourceDirectory
}
else {
git clone --branch main --depth 1 --quiet https://github.com/dotnet/performance $PerformanceDirectory
- if ($LASTEXITCODE -ne 0) {
- Write-Output "git clone failed with code $LASTEXITCODE"
- exit 1
- }
}
if($MonoDotnet -ne "")
{
$UsingMono = "true"
$MonoDotnetPath = (Join-Path $PayloadDirectory "dotnet-mono")
- Verified-Move-Item -Path $MonoDotnet -Destination $MonoDotnetPath
+ Move-Item -Path $MonoDotnet -Destination $MonoDotnetPath
}
if ($UseCoreRun) {
$NewCoreRoot = (Join-Path $PayloadDirectory "Core_Root")
- Verified-Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot
+ Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot
}
if ($UseBaselineCoreRun) {
$NewBaselineCoreRoot = (Join-Path $PayloadDirectory "Baseline_Core_Root")
- Verified-Move-Item -Path $BaselineCoreRootDirectory -Destination $NewBaselineCoreRoot
+ Move-Item -Path $BaselineCoreRootDirectory -Destination $NewBaselineCoreRoot
}
if ($AndroidMono) {
@@ -198,7 +148,7 @@ if ($AndroidMono) {
{
mkdir $WorkItemDirectory
}
- Verified-Copy-Item -Path "$SourceDirectory\artifacts\bin\AndroidSampleApp\arm64\Release\android-arm64\publish\apk\bin\HelloAndroid.apk" $PayloadDirectory
+ Copy-Item -path "$SourceDirectory\artifacts\bin\AndroidSampleApp\arm64\Release\android-arm64\publish\apk\bin\HelloAndroid.apk" $PayloadDirectory
$SetupArguments = $SetupArguments -replace $Architecture, 'arm64'
}
@@ -208,9 +158,9 @@ if ($iOSMono) {
mkdir $WorkItemDirectory
}
if($iOSLlvmBuild) {
- Verified-Copy-Item -Path "$SourceDirectory\iosHelloWorld\llvm" $PayloadDirectory\iosHelloWorld\llvm -Recurse
+ Copy-Item -path "$SourceDirectory\iosHelloWorld\llvm" $PayloadDirectory\iosHelloWorld\llvm -Recurse
} else {
- Verified-Copy-Item -Path "$SourceDirectory\iosHelloWorld\nollvm" $PayloadDirectory\iosHelloWorld\nollvm -Recurse
+ Copy-Item -path "$SourceDirectory\iosHelloWorld\nollvm" $PayloadDirectory\iosHelloWorld\nollvm -Recurse
}
$SetupArguments = $SetupArguments -replace $Architecture, 'arm64'
@@ -218,7 +168,6 @@ if ($iOSMono) {
$DocsDir = (Join-Path $PerformanceDirectory "docs")
robocopy $DocsDir $WorkItemDirectory
-Verify-Robocopy $DocsDir
# Set variables that we will need to have in future steps
$ci = $true
diff --git a/eng/testing/performance/performance-setup.sh b/eng/testing/performance/performance-setup.sh
index c897b1019aae6..cffd9ca8d6cdb 100755
--- a/eng/testing/performance/performance-setup.sh
+++ b/eng/testing/performance/performance-setup.sh
@@ -31,24 +31,6 @@ use_latest_dotnet=false
logical_machine=
javascript_engine="v8"
-verified_mv()
-{
- mv $1 $2
- if [ "$?" -ne "0" ]; then
- echo "Failed to move $1 to $2"
- exit 1
- fi
-}
-
-verified_rsync()
-{
- rsync -a --progress $1 $2
- if [ "$?" -ne "0" ]; then
- echo "Failed to sync $1 to $2"
- exit 1
- fi
-}
-
while (($# > 0)); do
lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
case $lowerI in
@@ -289,28 +271,24 @@ else
git clone --branch main --depth 1 --quiet https://github.com/dotnet/performance.git $performance_directory
# uncomment to use BenchmarkDotNet sources instead of nuget packages
# git clone https://github.com/dotnet/BenchmarkDotNet.git $benchmark_directory
- if [ "$?" -ne "0" ]; then
- echo "git clone failed with code $?"
- exit 1
- fi
-
+
docs_directory=$performance_directory/docs
- verified_mv $docs_directory $workitem_directory
+ mv $docs_directory $workitem_directory
fi
if [[ "$wasm_runtime_loc" != "" ]]; then
using_wasm=true
wasm_dotnet_path=$payload_directory/dotnet-wasm
- verified_mv $wasm_runtime_loc $wasm_dotnet_path
+ mv $wasm_runtime_loc $wasm_dotnet_path
# install emsdk, $source_directory/src/mono/wasm/ has the nuget.config with require feed. EMSDK may be available in the payload in a different directory, should visit this install to avoid deplicated payload.
pushd $source_directory/src/mono/wasm/
make provision-wasm
EMSDK_PATH = $source_directory/src/mono/wasm/emsdk
popd
# wasm aot and interpreter need some source code from dotnet\runtime repo
- verified_rsync -aq --progress $source_directory/* $wasm_dotnet_path --exclude Payload --exclude docs --exclude src/coreclr --exclude src/tests --exclude artifacts/obj --exclude artifacts/log --exclude artifacts/tests --exclude __download__
+ rsync -aq --progress $source_directory/* $wasm_dotnet_path --exclude Payload --exclude docs --exclude src/coreclr --exclude src/tests --exclude artifacts/obj --exclude artifacts/log --exclude artifacts/tests --exclude __download__
# copy wasm build drop to the location that aot and interpreter build expects
- verified_rsync -a --progress $wasm_dotnet_path/artifacts/BrowserWasm/artifacts/* $wasm_dotnet_path/artifacts
+ rsync -a --progress $wasm_dotnet_path/artifacts/BrowserWasm/artifacts/* $wasm_dotnet_path/artifacts
rm -r $wasm_dotnet_path/artifacts/BrowserWasm/artifacts
if [[ "$wasmaot" == "true" ]]; then
extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --wasmEngine /home/helixbot/.jsvu/$javascript_engine --runtimeSrcDir \$HELIX_CORRELATION_PAYLOAD/dotnet-wasm --aotcompilermode wasm --buildTimeout 3600"
@@ -322,23 +300,23 @@ fi
if [[ "$mono_dotnet" != "" ]] && [[ "$monoaot" == "false" ]]; then
using_mono=true
mono_dotnet_path=$payload_directory/dotnet-mono
- verified_mv $mono_dotnet $mono_dotnet_path
+ mv $mono_dotnet $mono_dotnet_path
fi
if [[ "$monoaot" == "true" ]]; then
monoaot_dotnet_path=$payload_directory/monoaot
- verified_mv $monoaot_path $monoaot_dotnet_path
+ mv $monoaot_path $monoaot_dotnet_path
extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --runtimes monoaotllvm --aotcompilerpath \$HELIX_CORRELATION_PAYLOAD/monoaot/sgen/mini/mono-sgen --customruntimepack \$HELIX_CORRELATION_PAYLOAD/monoaot/pack --aotcompilermode llvm"
fi
if [[ "$use_core_run" = true ]]; then
new_core_root=$payload_directory/Core_Root
- verified_mv $core_root_directory $new_core_root
+ mv $core_root_directory $new_core_root
fi
if [[ "$use_baseline_core_run" = true ]]; then
- new_baseline_core_root=$payload_directory/Baseline_Core_Root
- verified_mv $baseline_core_root_directory $new_baseline_core_root
+ new_baseline_core_root=$payload_directory/Baseline_Core_Root
+ mv $baseline_core_root_directory $new_baseline_core_root
fi
ci=true
diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets
index 58dbfac94db89..acce583b8a96c 100644
--- a/eng/testing/tests.mobile.targets
+++ b/eng/testing/tests.mobile.targets
@@ -42,6 +42,12 @@
$(AdditionalXHarnessArguments) --arg=-c=$(XUnitClassName)
+
+
+ $(AdditionalXHarnessArguments) -- -m=$(XUnitMethodName)
+ $(AdditionalXHarnessArguments) -- -c=$(XUnitClassName)
+
+
diff --git a/global.json b/global.json
index 6eac323f59052..7d377cb4057e7 100644
--- a/global.json
+++ b/global.json
@@ -12,12 +12,12 @@
"python3": "3.7.1"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.21474.2",
- "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21474.2",
- "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.21474.2",
- "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.21474.2",
+ "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "7.0.0-beta.21514.3",
+ "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21514.3",
+ "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.21514.3",
+ "Microsoft.DotNet.SharedFramework.Sdk": "7.0.0-beta.21514.3",
"Microsoft.Build.NoTargets": "3.1.0",
"Microsoft.Build.Traversal": "3.0.23",
- "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21476.2"
+ "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21511.2"
}
}
diff --git a/src/coreclr/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj b/src/coreclr/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj
index 95d6c747fb428..6c95feffc7d0e 100644
--- a/src/coreclr/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj
+++ b/src/coreclr/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj
@@ -2,6 +2,8 @@
+
+ false
CoreCLR application host for test applications.
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
index 74849de7d1ed8..fda6459b2551d 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs
@@ -30,9 +30,6 @@ internal RuntimeType[] GetDefinedTypes()
{
return GetTypes(this);
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool IsResource(RuntimeModule module);
#endregion
#region Module overrides
@@ -472,7 +469,8 @@ public override Guid ModuleVersionId
public override bool IsResource()
{
- return IsResource(this);
+ // CoreClr does not support resource-only modules.
+ return false;
}
[RequiresUnreferencedCode("Fields might be removed")]
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h
index 731e8305da695..1dfae365bc4db 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/standardpch.h
@@ -68,12 +68,14 @@
#ifdef TARGET_UNIX
#include "clr_std/string"
#include "clr_std/algorithm"
+#include "clr_std/vector"
#else // !TARGET_UNIX
#ifndef USE_STL
#define USE_STL
#endif // USE_STL
#include
#include
+#include
#endif // !TARGET_UNIX
#ifdef USE_MSVCDIS
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt b/src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt
index 92cda6d5600fe..4827c195dc299 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt
+++ b/src/coreclr/ToolBox/superpmi/superpmi/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SUPERPMI_SOURCES
jitdebugger.cpp
jitinstance.cpp
methodstatsemitter.cpp
+ metricssummary.cpp
neardiffer.cpp
parallelsuperpmi.cpp
superpmi.cpp
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp b/src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp
index e4d98a13752d6..c4735b23d7527 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/commandline.cpp
@@ -81,6 +81,16 @@ void CommandLine::DumpHelp(const char* program)
printf(" t - method throughput time\n");
printf(" * - all available method stats\n");
printf("\n");
+ printf(" -metricsSummary , -baseMetricsSummary \n");
+ printf(" Emit a summary of metrics to the specified file\n");
+ printf(" Currently includes:\n");
+ printf(" Total number of successful SPMI compiles\n");
+ printf(" Total number of failing SPMI compiles\n");
+ printf(" Total amount of ASM code in bytes\n");
+ printf("\n");
+ printf(" -diffMetricsSummary \n");
+ printf(" Same as above, but emit for the diff/second JIT");
+ printf("\n");
printf(" -a[pplyDiff]\n");
printf(" Compare the compile result generated from the provided JIT with the\n");
printf(" compile result stored with the MC. If two JITs are provided, this\n");
@@ -374,6 +384,26 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
o->methodStatsTypes = argv[i];
}
+ else if ((_strnicmp(&argv[i][1], "metricsSummary", argLen) == 0) || (_strnicmp(&argv[i][1], "baseMetricsSummary", argLen) == 0))
+ {
+ if (++i >= argc)
+ {
+ DumpHelp(argv[0]);
+ return false;
+ }
+
+ o->baseMetricsSummaryFile = argv[i];
+ }
+ else if ((_strnicmp(&argv[i][1], "diffMetricsSummary", argLen) == 0))
+ {
+ if (++i >= argc)
+ {
+ DumpHelp(argv[0]);
+ return false;
+ }
+
+ o->diffMetricsSummaryFile = argv[i];
+ }
else if ((_strnicmp(&argv[i][1], "applyDiff", argLen) == 0))
{
o->applyDiff = true;
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/commandline.h b/src/coreclr/ToolBox/superpmi/superpmi/commandline.h
index e9bae5740262b..055adf00295cd 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/commandline.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi/commandline.h
@@ -36,6 +36,8 @@ class CommandLine
, indexes(nullptr)
, hash(nullptr)
, methodStatsTypes(nullptr)
+ , baseMetricsSummaryFile(nullptr)
+ , diffMetricsSummaryFile(nullptr)
, mclFilename(nullptr)
, diffMCLFilename(nullptr)
, targetArchitecture(nullptr)
@@ -67,6 +69,8 @@ class CommandLine
int* indexes;
char* hash;
char* methodStatsTypes;
+ char* baseMetricsSummaryFile;
+ char* diffMetricsSummaryFile;
char* mclFilename;
char* diffMCLFilename;
char* targetArchitecture;
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp b/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp
index fafc367669d47..96484d4b86bcd 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.cpp
@@ -8,6 +8,7 @@
#include "jithost.h"
#include "errorhandling.h"
#include "spmiutil.h"
+#include "metricssummary.h"
JitInstance* JitInstance::InitJit(char* nameOfJit,
bool breakOnAssert,
@@ -276,7 +277,7 @@ bool JitInstance::reLoad(MethodContext* firstContext)
return true;
}
-JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput)
+JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput, MetricsSummary* metrics)
{
struct Param : FilterSuperPMIExceptionsParam_CaptureException
{
@@ -286,12 +287,14 @@ JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, i
unsigned flags;
int mcIndex;
bool collectThroughput;
+ MetricsSummary* metrics;
} param;
param.pThis = this;
param.result = RESULT_SUCCESS; // assume success
param.flags = 0;
param.mcIndex = mcIndex;
param.collectThroughput = collectThroughput;
+ param.metrics = metrics;
// store to instance field our raw values, so we can figure things out a bit later...
mc = MethodToCompile;
@@ -365,11 +368,16 @@ JitInstance::Result JitInstance::CompileMethod(MethodContext* MethodToCompile, i
pParam->pThis->mc->cr->recAllocGCInfoCapture();
pParam->pThis->mc->cr->recMessageLog("Successful Compile");
+
+ pParam->metrics->SuccessfulCompiles++;
+ pParam->metrics->NumCodeBytes += NCodeSizeBlock;
}
else
{
LogDebug("compileMethod failed with result %d", jitResult);
pParam->result = RESULT_ERROR;
+
+ pParam->metrics->FailingCompiles++;
}
}
PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndStop)
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h b/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h
index c572008481a65..8e8fbabf82ead 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi/jitinstance.h
@@ -60,7 +60,7 @@ class JitInstance
bool resetConfig(MethodContext* firstContext);
- Result CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput);
+ Result CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput, class MetricsSummary* summary);
const WCHAR* getForceOption(const WCHAR* key);
const WCHAR* getOption(const WCHAR* key);
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h b/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h
index 083d24fe852a9..40d38698b3d44 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi/methodstatsemitter.h
@@ -24,4 +24,5 @@ class MethodStatsEmitter
void Emit(int methodNumber, MethodContext* mc, ULONGLONG firstTime, ULONGLONG secondTime);
void SetStatsTypes(char* types);
};
+
#endif
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.cpp b/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.cpp
new file mode 100644
index 0000000000000..e7c725d7845bf
--- /dev/null
+++ b/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.cpp
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "standardpch.h"
+#include "metricssummary.h"
+#include "logging.h"
+
+struct HandleCloser
+{
+ void operator()(HANDLE hFile)
+ {
+ CloseHandle(hFile);
+ }
+};
+
+struct FileHandleWrapper
+{
+ FileHandleWrapper(HANDLE hFile)
+ : hFile(hFile)
+ {
+ }
+
+ ~FileHandleWrapper()
+ {
+ CloseHandle(hFile);
+ }
+
+ HANDLE get() { return hFile; }
+
+private:
+ HANDLE hFile;
+};
+
+bool MetricsSummary::SaveToFile(const char* path)
+{
+ FileHandleWrapper file(CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
+ if (file.get() == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+
+ char buffer[4096];
+ int len =
+ sprintf_s(buffer, sizeof(buffer), "Successful compiles,Failing compiles,Code bytes\n%d,%d,%lld\n",
+ SuccessfulCompiles, FailingCompiles, NumCodeBytes);
+ DWORD numWritten;
+ if (!WriteFile(file.get(), buffer, static_cast(len), &numWritten, nullptr) || numWritten != static_cast(len))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool MetricsSummary::LoadFromFile(const char* path, MetricsSummary* metrics)
+{
+ FileHandleWrapper file(CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+ if (file.get() == INVALID_HANDLE_VALUE)
+ {
+ return false;
+ }
+
+ LARGE_INTEGER len;
+ if (!GetFileSizeEx(file.get(), &len))
+ {
+ return false;
+ }
+
+ std::vector content(static_cast(len.QuadPart));
+ DWORD numRead;
+ if (!ReadFile(file.get(), content.data(), static_cast(content.size()), &numRead, nullptr) || numRead != content.size())
+ {
+ return false;
+ }
+
+ if (sscanf_s(content.data(), "Successful compiles,Failing compiles,Code bytes\n%d,%d,%lld\n",
+ &metrics->SuccessfulCompiles, &metrics->FailingCompiles, &metrics->NumCodeBytes) != 3)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void MetricsSummary::AggregateFrom(const MetricsSummary& other)
+{
+ SuccessfulCompiles += other.SuccessfulCompiles;
+ FailingCompiles += other.FailingCompiles;
+ NumCodeBytes += other.NumCodeBytes;
+}
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.h b/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.h
new file mode 100644
index 0000000000000..4f7d825c2d43a
--- /dev/null
+++ b/src/coreclr/ToolBox/superpmi/superpmi/metricssummary.h
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef _MetricsSummary
+#define _MetricsSummary
+
+class MetricsSummary
+{
+public:
+ int SuccessfulCompiles;
+ int FailingCompiles;
+ long long NumCodeBytes;
+
+ MetricsSummary()
+ : SuccessfulCompiles(0)
+ , FailingCompiles(0)
+ , NumCodeBytes(0)
+ {
+ }
+
+ bool SaveToFile(const char* path);
+ static bool LoadFromFile(const char* path, MetricsSummary* metrics);
+ void AggregateFrom(const MetricsSummary& other);
+};
+
+#endif
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp b/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
index 46c1a7a91132d..92b172e196d1c 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
@@ -8,6 +8,7 @@
#include "lightweightmap.h"
#include "commandline.h"
#include "errorhandling.h"
+#include "metricssummary.h"
#define MAX_LOG_LINE_SIZE 0x1000 // 4 KB
@@ -293,6 +294,35 @@ void ProcessChildStdOut(const CommandLine::Options& o,
}
}
+static bool ProcessChildMetrics(const char* baseMetricsSummaryPath, const char* diffMetricsSummaryPath, MetricsSummary* baseMetrics, MetricsSummary* diffMetrics)
+{
+ if (baseMetricsSummaryPath != nullptr)
+ {
+ MetricsSummary childBaseMetrics;
+ if (!MetricsSummary::LoadFromFile(baseMetricsSummaryPath, &childBaseMetrics))
+ {
+ LogError("Couldn't load base metrics summary created by child process");
+ return false;
+ }
+
+ baseMetrics->AggregateFrom(childBaseMetrics);
+ }
+
+ if (diffMetricsSummaryPath != nullptr)
+ {
+ MetricsSummary childDiffMetrics;
+ if (!MetricsSummary::LoadFromFile(diffMetricsSummaryPath, &childDiffMetrics))
+ {
+ LogError("Couldn't load diff metrics summary created by child process");
+ return false;
+ }
+
+ diffMetrics->AggregateFrom(childDiffMetrics);
+ }
+
+ return true;
+}
+
#ifndef TARGET_UNIX // TODO-Porting: handle Ctrl-C signals gracefully on Unix
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
@@ -309,15 +339,39 @@ int __cdecl compareInt(const void* arg1, const void* arg2)
return (*(const int*)arg1) - (*(const int*)arg2);
}
-// 'arrWorkerMCLPath' is an array of strings of size 'workerCount'.
-void MergeWorkerMCLs(char* mclFilename, char** arrWorkerMCLPath, int workerCount)
+struct PerWorkerData
+{
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+
+ char* failingMCListPath;
+ char* diffMCListPath;
+ char* stdOutputPath;
+ char* stdErrorPath;
+ char* baseMetricsSummaryPath;
+ char* diffMetricsSummaryPath;
+
+ PerWorkerData()
+ : hStdOutput(INVALID_HANDLE_VALUE)
+ , hStdError(INVALID_HANDLE_VALUE)
+ , failingMCListPath(nullptr)
+ , diffMCListPath(nullptr)
+ , stdOutputPath(nullptr)
+ , stdErrorPath(nullptr)
+ , baseMetricsSummaryPath(nullptr)
+ , diffMetricsSummaryPath(nullptr)
+ {
+ }
+};
+
+void MergeWorkerMCLs(char* mclFilename, PerWorkerData* workerData, int workerCount, char* PerWorkerData::*mclPath)
{
int **MCL = new int *[workerCount], *MCLCount = new int[workerCount], totalCount = 0;
for (int i = 0; i < workerCount; i++)
{
// Read the next partial MCL file
- ReadMCLToArray(arrWorkerMCLPath[i], &MCL[i], &MCLCount[i]);
+ ReadMCLToArray(workerData[i].*mclPath, &MCL[i], &MCLCount[i]);
totalCount += MCLCount[i];
}
@@ -474,14 +528,7 @@ int doParallelSuperPMI(CommandLine::Options& o)
LogVerbose(" diffMCLFilename=%s", o.diffMCLFilename);
LogVerbose(" workerCount=%d, skipCleanup=%d.", o.workerCount, o.skipCleanup);
- HANDLE* hProcesses = new HANDLE[o.workerCount];
- HANDLE* hStdOutput = new HANDLE[o.workerCount];
- HANDLE* hStdError = new HANDLE[o.workerCount];
-
- char** arrFailingMCListPath = new char*[o.workerCount];
- char** arrDiffMCListPath = new char*[o.workerCount];
- char** arrStdOutputPath = new char*[o.workerCount];
- char** arrStdErrorPath = new char*[o.workerCount];
+ PerWorkerData* perWorkerData = new PerWorkerData[o.workerCount];
// Add a random number to the temporary file names to allow multiple parallel SuperPMI to happen at once.
unsigned int randNumber = 0;
@@ -493,51 +540,71 @@ int doParallelSuperPMI(CommandLine::Options& o)
for (int i = 0; i < o.workerCount; i++)
{
+ PerWorkerData& wd = perWorkerData[i];
if (o.mclFilename != nullptr)
{
- arrFailingMCListPath[i] = new char[MAX_PATH];
- sprintf_s(arrFailingMCListPath[i], MAX_PATH, "%sParallelSuperPMI-%u-%d.mcl", tempPath, randNumber, i);
+ wd.failingMCListPath = new char[MAX_PATH];
+ sprintf_s(wd.failingMCListPath, MAX_PATH, "%sParallelSuperPMI-%u-%d.mcl", tempPath, randNumber, i);
}
- else
+
+ if (o.diffMCLFilename != nullptr)
{
- arrFailingMCListPath[i] = nullptr;
+ wd.diffMCListPath = new char[MAX_PATH];
+ sprintf_s(wd.diffMCListPath, MAX_PATH, "%sParallelSuperPMI-Diff-%u-%d.mcl", tempPath, randNumber, i);
}
- if (o.diffMCLFilename != nullptr)
+ if (o.baseMetricsSummaryFile != nullptr)
{
- arrDiffMCListPath[i] = new char[MAX_PATH];
- sprintf_s(arrDiffMCListPath[i], MAX_PATH, "%sParallelSuperPMI-Diff-%u-%d.mcl", tempPath, randNumber, i);
+ wd.baseMetricsSummaryPath = new char[MAX_PATH];
+ sprintf_s(wd.baseMetricsSummaryPath, MAX_PATH, "%sParallelSuperPMI-BaseMetricsSummary-%u-%d.txt", tempPath, randNumber, i);
}
- else
+
+ if (o.diffMetricsSummaryFile != nullptr)
{
- arrDiffMCListPath[i] = nullptr;
+ wd.diffMetricsSummaryPath = new char[MAX_PATH];
+ sprintf_s(wd.diffMetricsSummaryPath, MAX_PATH, "%sParallelSuperPMI-DiffMetricsSummary-%u-%d.txt", tempPath, randNumber, i);
}
- arrStdOutputPath[i] = new char[MAX_PATH];
- arrStdErrorPath[i] = new char[MAX_PATH];
+ wd.stdOutputPath = new char[MAX_PATH];
+ wd.stdErrorPath = new char[MAX_PATH];
- sprintf_s(arrStdOutputPath[i], MAX_PATH, "%sParallelSuperPMI-stdout-%u-%d.txt", tempPath, randNumber, i);
- sprintf_s(arrStdErrorPath[i], MAX_PATH, "%sParallelSuperPMI-stderr-%u-%d.txt", tempPath, randNumber, i);
+ sprintf_s(wd.stdOutputPath, MAX_PATH, "%sParallelSuperPMI-stdout-%u-%d.txt", tempPath, randNumber, i);
+ sprintf_s(wd.stdErrorPath, MAX_PATH, "%sParallelSuperPMI-stderr-%u-%d.txt", tempPath, randNumber, i);
}
char cmdLine[MAX_CMDLINE_SIZE];
cmdLine[0] = '\0';
int bytesWritten;
+ HANDLE* hProcesses = new HANDLE[o.workerCount];
for (int i = 0; i < o.workerCount; i++)
{
bytesWritten = sprintf_s(cmdLine, MAX_CMDLINE_SIZE, "%s -stride %d %d", spmiFilename, i + 1, o.workerCount);
- if (o.mclFilename != nullptr)
+ PerWorkerData& wd = perWorkerData[i];
+
+ if (wd.failingMCListPath != nullptr)
{
bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -failingMCList %s",
- arrFailingMCListPath[i]);
+ wd.failingMCListPath);
}
- if (o.diffMCLFilename != nullptr)
+ if (wd.diffMCListPath != nullptr)
{
bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -diffMCList %s",
- arrDiffMCListPath[i]);
+ wd.diffMCListPath);
+ }
+
+ if (wd.baseMetricsSummaryPath != nullptr)
+ {
+ bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -baseMetricsSummary %s",
+ wd.baseMetricsSummaryPath);
+ }
+
+ if (wd.diffMetricsSummaryPath != nullptr)
+ {
+ bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -diffMetricsSummary %s",
+ wd.diffMetricsSummaryPath);
}
if (o.failureLimit > 0)
@@ -553,26 +620,26 @@ int doParallelSuperPMI(CommandLine::Options& o)
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // Let newly created stdout/stderr handles be inherited.
- LogDebug("stdout %i=%s", i, arrStdOutputPath[i]);
- hStdOutput[i] = CreateFileA(arrStdOutputPath[i], GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS,
+ LogDebug("stdout %i=%s", i, wd.stdOutputPath);
+ wd.hStdOutput = CreateFileA(wd.stdOutputPath, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
- if (hStdOutput[i] == INVALID_HANDLE_VALUE)
+ if (wd.hStdOutput == INVALID_HANDLE_VALUE)
{
- LogError("Unable to open '%s'. GetLastError()=%u", arrStdOutputPath[i], GetLastError());
+ LogError("Unable to open '%s'. GetLastError()=%u", wd.stdOutputPath, GetLastError());
return -1;
}
- LogDebug("stderr %i=%s", i, arrStdErrorPath[i]);
- hStdError[i] = CreateFileA(arrStdErrorPath[i], GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS,
+ LogDebug("stderr %i=%s", i, wd.stdErrorPath);
+ wd.hStdError = CreateFileA(wd.stdErrorPath, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
- if (hStdError[i] == INVALID_HANDLE_VALUE)
+ if (wd.hStdError == INVALID_HANDLE_VALUE)
{
- LogError("Unable to open '%s'. GetLastError()=%u", arrStdErrorPath[i], GetLastError());
+ LogError("Unable to open '%s'. GetLastError()=%u", wd.stdErrorPath, GetLastError());
return -1;
}
// Create a SuperPMI worker process and redirect its output to file
- if (!StartProcess(cmdLine, hStdOutput[i], hStdError[i], &hProcesses[i]))
+ if (!StartProcess(cmdLine, wd.hStdOutput, wd.hStdError, &hProcesses[i]))
{
return -1;
}
@@ -583,8 +650,8 @@ int doParallelSuperPMI(CommandLine::Options& o)
// Close stdout/stderr
for (int i = 0; i < o.workerCount; i++)
{
- CloseHandle(hStdOutput[i]);
- CloseHandle(hStdError[i]);
+ CloseHandle(perWorkerData[i].hStdOutput);
+ CloseHandle(perWorkerData[i].hStdError);
}
SpmiResult result = SpmiResult::Success;
@@ -626,13 +693,18 @@ int doParallelSuperPMI(CommandLine::Options& o)
bool usageError = false; // variable to flag if we hit a usage error in SuperPMI
int loaded = 0, jitted = 0, failed = 0, excluded = 0, missing = 0, diffs = 0;
+ MetricsSummary baseMetrics;
+ MetricsSummary diffMetrics;
// Read the stderr files and log them as errors
// Read the stdout files and parse them for counts and log any MISSING or ISSUE errors
for (int i = 0; i < o.workerCount; i++)
{
- ProcessChildStdErr(arrStdErrorPath[i]);
- ProcessChildStdOut(o, arrStdOutputPath[i], &loaded, &jitted, &failed, &excluded, &missing, &diffs, &usageError);
+ PerWorkerData& wd = perWorkerData[i];
+ ProcessChildStdErr(wd.stdErrorPath);
+ ProcessChildStdOut(o, wd.stdOutputPath, &loaded, &jitted, &failed, &excluded, &missing, &diffs, &usageError);
+ ProcessChildMetrics(wd.baseMetricsSummaryPath, wd.diffMetricsSummaryPath, &baseMetrics, &diffMetrics);
+
if (usageError)
break;
}
@@ -640,13 +712,23 @@ int doParallelSuperPMI(CommandLine::Options& o)
if (o.mclFilename != nullptr && !usageError)
{
// Concat the resulting .mcl files
- MergeWorkerMCLs(o.mclFilename, arrFailingMCListPath, o.workerCount);
+ MergeWorkerMCLs(o.mclFilename, perWorkerData, o.workerCount, &PerWorkerData::failingMCListPath);
}
if (o.diffMCLFilename != nullptr && !usageError)
{
// Concat the resulting diff .mcl files
- MergeWorkerMCLs(o.diffMCLFilename, arrDiffMCListPath, o.workerCount);
+ MergeWorkerMCLs(o.diffMCLFilename, perWorkerData, o.workerCount, &PerWorkerData::diffMCListPath);
+ }
+
+ if (o.baseMetricsSummaryFile != nullptr && !usageError)
+ {
+ baseMetrics.SaveToFile(o.baseMetricsSummaryFile);
+ }
+
+ if (o.diffMetricsSummaryFile != nullptr && !usageError)
+ {
+ diffMetrics.SaveToFile(o.diffMetricsSummaryFile);
}
if (!usageError)
@@ -670,16 +752,25 @@ int doParallelSuperPMI(CommandLine::Options& o)
// Delete all temporary files generated
for (int i = 0; i < o.workerCount; i++)
{
- if (arrFailingMCListPath[i] != nullptr)
+ PerWorkerData& wd = perWorkerData[i];
+ if (wd.failingMCListPath != nullptr)
+ {
+ DeleteFile(wd.failingMCListPath);
+ }
+ if (wd.diffMCListPath != nullptr)
+ {
+ DeleteFile(wd.diffMCListPath);
+ }
+ if (wd.baseMetricsSummaryPath != nullptr)
{
- DeleteFile(arrFailingMCListPath[i]);
+ DeleteFile(wd.baseMetricsSummaryPath);
}
- if (arrDiffMCListPath[i] != nullptr)
+ if (wd.diffMetricsSummaryPath != nullptr)
{
- DeleteFile(arrDiffMCListPath[i]);
+ DeleteFile(wd.diffMetricsSummaryPath);
}
- DeleteFile(arrStdOutputPath[i]);
- DeleteFile(arrStdErrorPath[i]);
+ DeleteFile(wd.stdOutputPath);
+ DeleteFile(wd.stdErrorPath);
}
}
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp b/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
index 640dfd367a7f3..5410240bdad33 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
@@ -18,6 +18,7 @@
#include "mclist.h"
#include "methodstatsemitter.h"
#include "spmiutil.h"
+#include "metricssummary.h"
extern int doParallelSuperPMI(CommandLine::Options& o);
@@ -264,6 +265,9 @@ int __cdecl main(int argc, char* argv[])
}
}
+ MetricsSummary baseMetrics;
+ MetricsSummary diffMetrics;
+
while (true)
{
MethodContextBuffer mcb = reader->GetNextMethodContext();
@@ -360,7 +364,7 @@ int __cdecl main(int argc, char* argv[])
jittedCount++;
st3.Start();
- res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput);
+ res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput, &baseMetrics);
st3.Stop();
LogDebug("Method %d compiled in %fms, result %d", reader->GetMethodContextIndex(), st3.GetMilliseconds(), res);
@@ -378,7 +382,7 @@ int __cdecl main(int argc, char* argv[])
mc->cr = new CompileResult();
st4.Start();
- res2 = jit2->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput);
+ res2 = jit2->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput, &diffMetrics);
st4.Stop();
LogDebug("Method %d compiled by JIT2 in %fms, result %d", reader->GetMethodContextIndex(),
st4.GetMilliseconds(), res2);
@@ -603,6 +607,16 @@ int __cdecl main(int argc, char* argv[])
st2.Stop();
LogVerbose("Total time: %fms", st2.GetMilliseconds());
+ if (o.baseMetricsSummaryFile != nullptr)
+ {
+ baseMetrics.SaveToFile(o.baseMetricsSummaryFile);
+ }
+
+ if (o.diffMetricsSummaryFile != nullptr)
+ {
+ diffMetrics.SaveToFile(o.diffMetricsSummaryFile);
+ }
+
if (methodStatsEmitter != nullptr)
{
delete methodStatsEmitter;
diff --git a/src/coreclr/binder/bindertracing.cpp b/src/coreclr/binder/bindertracing.cpp
index b03eb2f66db5f..499e20d928887 100644
--- a/src/coreclr/binder/bindertracing.cpp
+++ b/src/coreclr/binder/bindertracing.cpp
@@ -147,12 +147,12 @@ namespace
DomainAssembly *parentAssembly = spec->GetParentAssembly();
if (parentAssembly != nullptr)
{
- PEAssembly *peAssembly = parentAssembly->GetFile();
- _ASSERTE(peAssembly != nullptr);
- peAssembly->GetDisplayName(request.RequestingAssembly);
+ PEAssembly *pPEAssembly = parentAssembly->GetPEAssembly();
+ _ASSERTE(pPEAssembly != nullptr);
+ pPEAssembly->GetDisplayName(request.RequestingAssembly);
AppDomain *domain = parentAssembly->GetAppDomain();
- AssemblyBinder *binder = peAssembly->GetAssemblyBinder();
+ AssemblyBinder *binder = pPEAssembly->GetAssemblyBinder();
GetAssemblyLoadContextNameFromBinder(binder, domain, request.RequestingAssemblyLoadContext);
}
diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp
index 8ab327eb15578..70e0007d6925b 100644
--- a/src/coreclr/debug/createdump/crashinfo.cpp
+++ b/src/coreclr/debug/createdump/crashinfo.cpp
@@ -13,6 +13,8 @@ CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t s
m_pid(pid),
m_ppid(-1),
m_hdac(nullptr),
+ m_pClrDataEnumRegions(nullptr),
+ m_pClrDataProcess(nullptr),
m_gatherFrames(gatherFrames),
m_crashThread(crashThread),
m_signal(signal),
@@ -44,6 +46,15 @@ CrashInfo::~CrashInfo()
}
m_moduleInfos.clear();
+ // Clean up DAC interfaces
+ if (m_pClrDataEnumRegions != nullptr)
+ {
+ m_pClrDataEnumRegions->Release();
+ }
+ if (m_pClrDataProcess != nullptr)
+ {
+ m_pClrDataProcess->Release();
+ }
// Unload DAC module
if (m_hdac != nullptr)
{
@@ -190,8 +201,16 @@ CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
thread->GetThreadStack();
}
}
- // Gather all the useful memory regions from the DAC
- if (!EnumerateMemoryRegionsWithDAC(minidumpType))
+ // Load and initialize DAC interfaces
+ if (!InitializeDAC())
+ {
+ return false;
+ }
+ if (!EnumerateManagedModules())
+ {
+ return false;
+ }
+ if (!UnwindAllThreads())
{
return false;
}
@@ -204,19 +223,15 @@ CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
// Enumerate all the memory regions using the DAC memory region support given a minidump type
//
bool
-CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
+CrashInfo::InitializeDAC()
{
ReleaseHolder dataTarget = new DumpDataTarget(*this);
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
- ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr;
- IXCLRDataProcess* pClrDataProcess = nullptr;
- HRESULT hr = S_OK;
bool result = false;
+ HRESULT hr = S_OK;
if (!m_coreclrPath.empty())
{
- TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration STARTED\n");
-
// We assume that the DAC is in the same location as the libcoreclr.so module
std::string dacPath;
dacPath.append(m_coreclrPath);
@@ -235,140 +250,156 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
goto exit;
}
- if ((minidumpType & MiniDumpWithFullMemory) == 0)
- {
- hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), dataTarget, (void**)&pClrDataEnumRegions);
- if (FAILED(hr))
- {
- fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
- goto exit;
- }
- // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
- hr = pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
- if (FAILED(hr))
- {
- fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
- goto exit;
- }
- }
- hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), dataTarget, (void**)&pClrDataProcess);
+ hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), dataTarget, (void**)&m_pClrDataEnumRegions);
if (FAILED(hr))
{
- fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr);
+ fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr);
goto exit;
}
- TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration FINISHED\n");
- if (!EnumerateManagedModules(pClrDataProcess))
+ hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), dataTarget, (void**)&m_pClrDataProcess);
+ if (FAILED(hr))
{
+ fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr);
goto exit;
}
}
- else {
- TRACE("EnumerateMemoryRegionsWithDAC: coreclr not found; not using DAC\n");
- }
- if (!UnwindAllThreads(pClrDataProcess))
+ else
{
- goto exit;
+ TRACE("InitializeDAC: coreclr not found; not using DAC\n");
}
result = true;
exit:
- if (pClrDataEnumRegions != nullptr)
- {
- pClrDataEnumRegions->Release();
- }
- if (pClrDataProcess != nullptr)
+ return result;
+}
+
+//
+// Enumerate all the memory regions using the DAC memory region support given a minidump type
+//
+bool
+CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
+{
+ if (m_pClrDataEnumRegions != nullptr && (minidumpType & MiniDumpWithFullMemory) == 0)
{
- pClrDataProcess->Release();
+ TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration STARTED\n");
+
+ // Since on both Linux and MacOS all the RW regions will be added for heap
+ // dumps by createdump, the only thing differentiating a MiniDumpNormal and
+ // a MiniDumpWithPrivateReadWriteMemory is that the later uses the EnumMemory
+ // APIs. This is kind of expensive on larger applications (4 minutes, or even
+ // more), and this should already be in RW pages. Change the dump type to the
+ // faster normal one. This one already ensures necessary DAC globals, etc.
+ // without the costly assembly, module, class, type runtime data structures
+ // enumeration.
+ if (minidumpType & MiniDumpWithPrivateReadWriteMemory)
+ {
+ char* fastHeapDumps = getenv("COMPlus_DbgEnableFastHeapDumps");
+ if (fastHeapDumps != nullptr && strcmp(fastHeapDumps, "1") == 0)
+ {
+ minidumpType = MiniDumpNormal;
+ }
+ }
+ // Calls CrashInfo::EnumMemoryRegion for each memory region found by the DAC
+ HRESULT hr = m_pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT);
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr);
+ return false;
+ }
+ TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration FINISHED\n");
}
- return result;
+ return true;
}
//
// Enumerate all the managed modules and replace the module mapping with the module name found.
//
bool
-CrashInfo::EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess)
+CrashInfo::EnumerateManagedModules()
{
CLRDATA_ENUM enumModules = 0;
- bool result = true;
HRESULT hr = S_OK;
- if (FAILED(hr = pClrDataProcess->StartEnumModules(&enumModules))) {
- fprintf(stderr, "StartEnumModules FAILED %08x\n", hr);
- return false;
- }
-
- while (true)
+ if (m_pClrDataProcess != nullptr)
{
- ReleaseHolder pClrDataModule;
- if ((hr = pClrDataProcess->EnumModule(&enumModules, &pClrDataModule)) != S_OK) {
- break;
- }
+ TRACE("EnumerateManagedModules: Module enumeration STARTED\n");
- // Skip any dynamic modules. The Request call below on some DACs crashes on dynamic modules.
- ULONG32 flags;
- if ((hr = pClrDataModule->GetFlags(&flags)) != S_OK) {
- TRACE("MODULE: GetFlags FAILED %08x\n", hr);
- continue;
- }
- if (flags & CLRDATA_MODULE_IS_DYNAMIC) {
- TRACE("MODULE: Skipping dynamic module\n");
- continue;
+ if (FAILED(hr = m_pClrDataProcess->StartEnumModules(&enumModules))) {
+ fprintf(stderr, "StartEnumModules FAILED %08x\n", hr);
+ return false;
}
- DacpGetModuleData moduleData;
- if (SUCCEEDED(hr = moduleData.Request(pClrDataModule.GetPtr())))
+ while (true)
{
- TRACE("MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, (uint64_t)moduleData.LoadedPEAddress, moduleData.IsDynamic,
- moduleData.IsInMemory, moduleData.IsFileLayout, (uint64_t)moduleData.PEFile, (uint64_t)moduleData.InMemoryPdbAddress);
+ ReleaseHolder pClrDataModule;
+ if ((hr = m_pClrDataProcess->EnumModule(&enumModules, &pClrDataModule)) != S_OK) {
+ break;
+ }
- if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0)
+ // Skip any dynamic modules. The Request call below on some DACs crashes on dynamic modules.
+ ULONG32 flags;
+ if ((hr = pClrDataModule->GetFlags(&flags)) != S_OK) {
+ TRACE("MODULE: GetFlags FAILED %08x\n", hr);
+ continue;
+ }
+ if (flags & CLRDATA_MODULE_IS_DYNAMIC) {
+ TRACE("MODULE: Skipping dynamic module\n");
+ continue;
+ }
+
+ DacpGetModuleData moduleData;
+ if (SUCCEEDED(hr = moduleData.Request(pClrDataModule.GetPtr())))
{
- ArrayHolder wszUnicodeName = new WCHAR[MAX_LONGPATH + 1];
- if (SUCCEEDED(hr = pClrDataModule->GetFileName(MAX_LONGPATH, nullptr, wszUnicodeName)))
+ TRACE("MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, (uint64_t)moduleData.LoadedPEAddress, moduleData.IsDynamic,
+ moduleData.IsInMemory, moduleData.IsFileLayout, (uint64_t)moduleData.PEAssembly, (uint64_t)moduleData.InMemoryPdbAddress);
+
+ if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0)
{
- std::string moduleName = FormatString("%S", wszUnicodeName.GetPtr());
+ ArrayHolder wszUnicodeName = new WCHAR[MAX_LONGPATH + 1];
+ if (SUCCEEDED(hr = pClrDataModule->GetFileName(MAX_LONGPATH, nullptr, wszUnicodeName)))
+ {
+ std::string moduleName = FormatString("%S", wszUnicodeName.GetPtr());
- // Change the module mapping name
- ReplaceModuleMapping(moduleData.LoadedPEAddress, moduleData.LoadedPESize, moduleName);
+ // Change the module mapping name
+ ReplaceModuleMapping(moduleData.LoadedPEAddress, moduleData.LoadedPESize, moduleName);
- // Add managed module info
- AddModuleInfo(true, moduleData.LoadedPEAddress, pClrDataModule, moduleName);
+ // Add managed module info
+ AddModuleInfo(true, moduleData.LoadedPEAddress, pClrDataModule, moduleName);
+ }
+ else {
+ TRACE("\nModule.GetFileName FAILED %08x\n", hr);
+ }
}
else {
- TRACE("\nModule.GetFileName FAILED %08x\n", hr);
+ TRACE("\n");
}
}
else {
- TRACE("\n");
+ TRACE("moduleData.Request FAILED %08x\n", hr);
}
}
- else {
- TRACE("moduleData.Request FAILED %08x\n", hr);
- }
- }
- if (enumModules != 0) {
- pClrDataProcess->EndEnumModules(enumModules);
+ if (enumModules != 0) {
+ m_pClrDataProcess->EndEnumModules(enumModules);
+ }
+ TRACE("EnumerateManagedModules: Module enumeration FINISHED\n");
}
-
- return result;
+ return true;
}
//
// Unwind all the native threads to ensure that the dwarf unwind info is added to the core dump.
//
bool
-CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess)
+CrashInfo::UnwindAllThreads()
{
ReleaseHolder pSos = nullptr;
- if (pClrDataProcess != nullptr) {
- pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
+ if (m_pClrDataProcess != nullptr) {
+ m_pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
}
// For each native and managed thread
for (ThreadInfo* thread : m_threads)
{
- if (!thread->UnwindThread(pClrDataProcess, pSos)) {
+ if (!thread->UnwindThread(m_pClrDataProcess, pSos)) {
return false;
}
}
@@ -827,5 +858,5 @@ FormatGuid(const GUID* guid)
{
uint8_t* bytes = (uint8_t*)guid;
return FormatString("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- bytes[3], bytes[2], bytes[1], bytes[0], bytes[5], bytes[4], bytes[7], bytes[6], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
+ bytes[3], bytes[2], bytes[1], bytes[0], bytes[5], bytes[4], bytes[7], bytes[6], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
}
diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h
index ca8f77994ac75..e100b7f216102 100644
--- a/src/coreclr/debug/createdump/crashinfo.h
+++ b/src/coreclr/debug/createdump/crashinfo.h
@@ -47,6 +47,8 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
pid_t m_ppid; // parent pid
pid_t m_tgid; // process group
HMODULE m_hdac; // dac module handle when loaded
+ ICLRDataEnumMemoryRegions* m_pClrDataEnumRegions; // dac enumerate memory interface instance
+ IXCLRDataProcess* m_pClrDataProcess; // dac process interface instance
bool m_gatherFrames; // if true, add the native and managed stack frames to the thread info
pid_t m_crashThread; // crashing thread id or 0 if none
uint32_t m_signal; // crash signal code or 0 if none
@@ -84,6 +86,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
void CleanupAndResumeProcess();
bool EnumerateAndSuspendThreads();
bool GatherCrashInfo(MINIDUMP_TYPE minidumpType);
+ bool EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType);
bool ReadMemory(void* address, void* buffer, size_t size); // read memory and add to dump
bool ReadProcessMemory(void* address, void* buffer, size_t size, size_t* read); // read raw memory
uint64_t GetBaseAddressFromAddress(uint64_t address);
@@ -137,9 +140,9 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
void VisitProgramHeader(uint64_t loadbias, uint64_t baseAddress, ElfW(Phdr)* phdr);
bool EnumerateModuleMappings();
#endif
- bool EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType);
- bool EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess);
- bool UnwindAllThreads(IXCLRDataProcess* pClrDataProcess);
+ bool InitializeDAC();
+ bool EnumerateManagedModules();
+ bool UnwindAllThreads();
void ReplaceModuleMapping(CLRDATA_ADDRESS baseAddress, ULONG64 size, const std::string& pszName);
void InsertMemoryBackedRegion(const MemoryRegion& region);
void InsertMemoryRegion(const MemoryRegion& region);
diff --git a/src/coreclr/debug/createdump/createdumpunix.cpp b/src/coreclr/debug/createdump/createdumpunix.cpp
index b789c98b820f1..6107adc625efc 100644
--- a/src/coreclr/debug/createdump/createdumpunix.cpp
+++ b/src/coreclr/debug/createdump/createdumpunix.cpp
@@ -47,7 +47,12 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP
CrashReportWriter crashReportWriter(*crashInfo);
crashReportWriter.WriteCrashReport(dumpPath);
}
- printf("Writing %s to file %s\n", dumpType, dumpPath.c_str());
+ // Gather all the useful memory regions from the DAC
+ if (!crashInfo->EnumerateMemoryRegionsWithDAC(minidumpType))
+ {
+ goto exit;
+ }
+ fprintf(stdout, "Writing %s to file %s\n", dumpType, dumpPath.c_str());
// Write the actual dump file
if (!dumpWriter.OpenDump(dumpPath.c_str()))
diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp
index 0630cfa710a37..35b834542c91c 100644
--- a/src/coreclr/debug/daccess/daccess.cpp
+++ b/src/coreclr/debug/daccess/daccess.cpp
@@ -679,11 +679,6 @@ MetaEnum::New(Module* mod,
*handle = TO_CDENUM(NULL);
}
- if (!mod->GetFile()->HasMetadata())
- {
- return S_FALSE;
- }
-
metaEnum = new (nothrow) MetaEnum;
if (!metaEnum)
{
@@ -4079,9 +4074,9 @@ ClrDataAccess::GetModuleByAddress(
{
TADDR base;
ULONG32 length;
- PEFile* file = modDef->GetFile();
+ PEAssembly* pPEAssembly = modDef->GetPEAssembly();
- if ((base = PTR_TO_TADDR(file->GetLoadedImageContents(&length))))
+ if ((base = PTR_TO_TADDR(pPEAssembly->GetLoadedImageContents(&length))))
{
if (TO_CDADDR(base) <= address &&
TO_CDADDR(base + length) > address)
@@ -4133,9 +4128,9 @@ ClrDataAccess::StartEnumMethodDefinitionsByAddress(
{
TADDR base;
ULONG32 length;
- PEFile* file = modDef->GetFile();
+ PEAssembly* assembly = modDef->GetPEAssembly();
- if ((base = PTR_TO_TADDR(file->GetLoadedImageContents(&length))))
+ if ((base = PTR_TO_TADDR(assembly->GetLoadedImageContents(&length))))
{
if (TO_CDADDR(base) <= address &&
TO_CDADDR(base + length) > address)
@@ -6459,7 +6454,7 @@ ClrDataAccess::GetHostGcNotificationTable()
}
/* static */ bool
-ClrDataAccess::GetMetaDataFileInfoFromPEFile(PEFile *pPEFile,
+ClrDataAccess::GetMetaDataFileInfoFromPEFile(PEAssembly *pPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
DWORD &dwDataSize,
@@ -6477,7 +6472,7 @@ ClrDataAccess::GetMetaDataFileInfoFromPEFile(PEFile *pPEFile,
isNGEN = false;
if (pDir == NULL || pDir->Size == 0)
{
- mdImage = pPEFile->GetILimage();
+ mdImage = pPEAssembly->GetPEImage();
if (mdImage != NULL)
{
layout = mdImage->GetLoadedLayout();
@@ -6526,7 +6521,7 @@ ClrDataAccess::GetMetaDataFileInfoFromPEFile(PEFile *pPEFile,
}
/* static */
-bool ClrDataAccess::GetILImageInfoFromNgenPEFile(PEFile *peFile,
+bool ClrDataAccess::GetILImageInfoFromNgenPEFile(PEAssembly *pPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
__out_ecount(cchFilePath) LPWSTR wszFilePath,
@@ -6536,10 +6531,10 @@ bool ClrDataAccess::GetILImageInfoFromNgenPEFile(PEFile *peFile,
DWORD dwWritten = 0;
// use the IL File name
- if (!peFile->GetPath().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten)))
+ if (!pPEAssembly->GetPath().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten)))
{
// Use DAC hint to retrieve the IL name.
- peFile->GetModuleFileNameHint().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten));
+ pPEAssembly->GetModuleFileNameHint().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten));
}
dwTimeStamp = 0;
dwSize = 0;
@@ -6603,7 +6598,7 @@ bool ClrDataAccess::GetILImageNameFromNgenImage( LPCWSTR ilExtension,
#endif // FEATURE_CORESYSTEM
void *
-ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
+ClrDataAccess::GetMetaDataFromHost(PEAssembly* pPEAssembly,
bool* isAlternate)
{
DWORD imageTimestamp, imageSize, dataSize;
@@ -6634,7 +6629,7 @@ ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
// so the field remains for now.
if (!ClrDataAccess::GetMetaDataFileInfoFromPEFile(
- peFile,
+ pPEAssembly,
imageTimestamp,
imageSize,
dataSize,
@@ -6647,7 +6642,7 @@ ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
}
// try direct match for the image that is loaded into the managed process
- peFile->GetLoadedMetadata((COUNT_T *)(&dataSize));
+ pPEAssembly->GetLoadedMetadata((COUNT_T *)(&dataSize));
DWORD allocSize = 0;
if (!ClrSafeInt::addition(dataSize, sizeof(DAC_INSTANCE), allocSize))
@@ -6665,7 +6660,7 @@ ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
buffer = (void*)(inst + 1);
// APIs implemented by hosting debugger. It can use the path/filename, timestamp, and
- // file size to find an exact match for the image. If that fails for an ngen'ed image,
+ // pPEAssembly size to find an exact match for the image. If that fails for an ngen'ed image,
// we can request the IL image which it came from.
if (m_legacyMetaDataLocator)
{
@@ -6701,7 +6696,7 @@ ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
//
isAlt = true;
if (!ClrDataAccess::GetILImageInfoFromNgenPEFile(
- peFile,
+ pPEAssembly,
imageTimestamp,
imageSize,
uniPath,
@@ -6781,13 +6776,13 @@ ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
-// Given a PEFile or a ReflectionModule try to find the corresponding metadata
+// Given a PEAssembly or a ReflectionModule try to find the corresponding metadata
// We will first ask debugger to locate it. If fail, we will try
// to get it from the target process
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IMDInternalImport*
-ClrDataAccess::GetMDImport(const PEFile* peFile, const ReflectionModule* reflectionModule, bool throwEx)
+ClrDataAccess::GetMDImport(const PEAssembly* pPEAssembly, const ReflectionModule* reflectionModule, bool throwEx)
{
HRESULT status;
PTR_CVOID mdBaseTarget = NULL;
@@ -6796,22 +6791,22 @@ ClrDataAccess::GetMDImport(const PEFile* peFile, const ReflectionModule* reflect
PVOID mdBaseHost = NULL;
bool isAlternate = false;
- _ASSERTE((peFile == NULL && reflectionModule != NULL) || (peFile != NULL && reflectionModule == NULL));
- TADDR peFileAddr = (peFile != NULL) ? dac_cast(peFile) : dac_cast(reflectionModule);
+ _ASSERTE((pPEAssembly == NULL && reflectionModule != NULL) || (pPEAssembly != NULL && reflectionModule == NULL));
+ TADDR peAssemblyAddr = (pPEAssembly != NULL) ? dac_cast(pPEAssembly) : dac_cast(reflectionModule);
//
// Look for one we've already created.
//
- mdImport = m_mdImports.Get(peFileAddr);
+ mdImport = m_mdImports.Get(peAssemblyAddr);
if (mdImport != NULL)
{
return mdImport;
}
- if (peFile != NULL)
+ if (pPEAssembly != NULL)
{
// Get the metadata size
- mdBaseTarget = ((PEFile*)peFile)->GetLoadedMetadata(&mdSize);
+ mdBaseTarget = const_cast(pPEAssembly)->GetLoadedMetadata(&mdSize);
}
else if (reflectionModule != NULL)
{
@@ -6862,12 +6857,12 @@ ClrDataAccess::GetMDImport(const PEFile* peFile, const ReflectionModule* reflect
}
// Try to see if debugger can locate it
- if (peFile != NULL && mdBaseHost == NULL && (m_target3 || m_legacyMetaDataLocator))
+ if (pPEAssembly != NULL && mdBaseHost == NULL && (m_target3 || m_legacyMetaDataLocator))
{
// We couldn't read the metadata from memory. Ask
// the target for metadata as it may be able to
// provide it from some alternate means.
- mdBaseHost = GetMetaDataFromHost(const_cast(peFile), &isAlternate);
+ mdBaseHost = GetMetaDataFromHost(const_cast(pPEAssembly), &isAlternate);
}
if (mdBaseHost == NULL)
@@ -6902,7 +6897,7 @@ ClrDataAccess::GetMDImport(const PEFile* peFile, const ReflectionModule* reflect
// The m_mdImports list does get cleaned up by calls to ClrDataAccess::Flush,
// i.e. every time the process changes state.
- if (m_mdImports.Add(peFileAddr, mdImport, isAlternate) == NULL)
+ if (m_mdImports.Add(peAssemblyAddr, mdImport, isAlternate) == NULL)
{
mdImport->Release();
DacError(E_OUTOFMEMORY);
@@ -6970,9 +6965,9 @@ HRESULT ClrDataAccess::VerifyDlls()
}
// Read the debug directory timestamp from the target mscorwks image using DAC
- // Note that we don't use the PE timestamp because the PE file might be changed in ways
+ // Note that we don't use the PE timestamp because the PE pPEAssembly might be changed in ways
// that don't effect the PDB (and therefore don't effect DAC). Specifically, we rebase
- // our DLLs at the end of a build, that changes the PE file, but not the PDB.
+ // our DLLs at the end of a build, that changes the PE pPEAssembly, but not the PDB.
// Note that if we wanted to be extra careful, we could read the CV contents (which includes
// the GUID signature) and verify it matches. Using the timestamp is useful for helpful error
// messages, and should be sufficient in any real scenario.
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp
index 20bb5ff3e0847..c6af447d1b13a 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.cpp
+++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp
@@ -272,7 +272,7 @@ DacDbiInterfaceImpl::DacDbiInterfaceImpl(
) : ClrDataAccess(pTarget),
m_pAllocator(pAllocator),
m_pMetaDataLookup(pMetaDataLookup),
- m_pCachedPEFile(VMPTR_PEFile::NullPtr()),
+ m_pCachedPEAssembly(VMPTR_PEAssembly::NullPtr()),
m_pCachedImporter(NULL),
m_isCachedHijackFunctionValid(FALSE)
{
@@ -307,7 +307,7 @@ DacDbiInterfaceImpl::~DacDbiInterfaceImpl()
// Called from DAC-ized code to get a IMDInternalImport
//
// Arguments:
-// pPEFile - PE file for which to get importer for
+// pPEAssembly - PE file for which to get importer for
// fThrowEx - if true, throw instead of returning NULL.
//
// Returns:
@@ -324,7 +324,7 @@ DacDbiInterfaceImpl::~DacDbiInterfaceImpl()
// This is an Internal importer, not a public Metadata importer.
//
interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
- const PEFile* pPEFile,
+ const PEAssembly* pPEAssembly,
const ReflectionModule * pReflectionModule,
bool fThrowEx)
{
@@ -335,23 +335,23 @@ interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
IDacDbiInterface::IMetaDataLookup * pLookup = m_pMetaDataLookup;
_ASSERTE(pLookup != NULL);
- VMPTR_PEFile vmPEFile = VMPTR_PEFile::NullPtr();
+ VMPTR_PEAssembly vmPEAssembly = VMPTR_PEAssembly::NullPtr();
- if (pPEFile != NULL)
+ if (pPEAssembly != NULL)
{
- vmPEFile.SetHostPtr(pPEFile);
+ vmPEAssembly.SetHostPtr(pPEAssembly);
}
else if (pReflectionModule != NULL)
{
// SOS and ClrDataAccess rely on special logic to find the metadata for methods in dynamic modules.
// We don't need to. The RS has already taken care of the special logic for us.
- // So here we just grab the PEFile off of the ReflectionModule and continue down the normal
+ // So here we just grab the PEAssembly off of the ReflectionModule and continue down the normal
// code path. See code:ClrDataAccess::GetMDImport for comparison.
- vmPEFile.SetHostPtr(pReflectionModule->GetFile());
+ vmPEAssembly.SetHostPtr(pReflectionModule->GetPEAssembly());
}
// Optimize for the case where the VM queries the same Importer many times in a row.
- if (m_pCachedPEFile == vmPEFile)
+ if (m_pCachedPEAssembly == vmPEAssembly)
{
return m_pCachedImporter;
}
@@ -370,7 +370,7 @@ interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
// To get the old codepath that uses the v2 metadata lookup methods,
// you'd have to load DAC only and then you'll get ClrDataAccess's implementation
// of this function.
- pInternal = pLookup->LookupMetaData(vmPEFile, isILMetaDataForNI);
+ pInternal = pLookup->LookupMetaData(vmPEAssembly, isILMetaDataForNI);
}
EX_CATCH
{
@@ -397,7 +397,7 @@ interface IMDInternalImport* DacDbiInterfaceImpl::GetMDImport(
else
{
// Cache it such that it we look for the exact same Importer again, we'll return it.
- m_pCachedPEFile = vmPEFile;
+ m_pCachedPEAssembly = vmPEAssembly;
m_pCachedImporter = pInternal;
}
@@ -445,7 +445,7 @@ HRESULT DacDbiInterfaceImpl::FlushCache()
// That would remove host DAC instances while they're being used.
DD_NON_REENTRANT_MAY_THROW;
- m_pCachedPEFile = VMPTR_PEFile::NullPtr();
+ m_pCachedPEAssembly = VMPTR_PEAssembly::NullPtr();
m_pCachedImporter = NULL;
m_isCachedHijackFunctionValid = FALSE;
@@ -1227,7 +1227,7 @@ mdSignature DacDbiInterfaceImpl::GetILCodeAndSigHelper(Module * pModule,
}
-bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
+bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
bool &isNGEN,
@@ -1237,14 +1237,14 @@ bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
DWORD dwDataSize;
DWORD dwRvaHint;
- PEFile * pPEFile = vmPEFile.GetDacPtr();
- _ASSERTE(pPEFile != NULL);
- if (pPEFile == NULL)
+ PEAssembly * pPEAssembly = vmPEAssembly.GetDacPtr();
+ _ASSERTE(pPEAssembly != NULL);
+ if (pPEAssembly == NULL)
return false;
WCHAR wszFilePath[MAX_LONGPATH] = {0};
DWORD cchFilePath = MAX_LONGPATH;
- bool ret = ClrDataAccess::GetMetaDataFileInfoFromPEFile(pPEFile,
+ bool ret = ClrDataAccess::GetMetaDataFileInfoFromPEFile(pPEAssembly,
dwTimeStamp,
dwSize,
dwDataSize,
@@ -1258,7 +1258,7 @@ bool DacDbiInterfaceImpl::GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
}
-bool DacDbiInterfaceImpl::GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
+bool DacDbiInterfaceImpl::GetILImageInfoFromNgenPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
IStringHolder* pStrFilename)
@@ -4137,16 +4137,16 @@ BOOL DacDbiInterfaceImpl::GetModulePath(VMPTR_Module vmModule,
DD_ENTER_MAY_THROW;
Module * pModule = vmModule.GetDacPtr();
- PEFile * pFile = pModule->GetFile();
- if (pFile != NULL)
+ PEAssembly * pPEAssembly = pModule->GetPEAssembly();
+ if (pPEAssembly != NULL)
{
- if( !pFile->GetPath().IsEmpty() )
+ if( !pPEAssembly->GetPath().IsEmpty() )
{
// Module has an on-disk path
- const WCHAR * szPath = pFile->GetPath().DacGetRawUnicode();
+ const WCHAR * szPath = pPEAssembly->GetPath().DacGetRawUnicode();
if (szPath == NULL)
{
- szPath = pFile->GetModuleFileNameHint().DacGetRawUnicode();
+ szPath = pPEAssembly->GetModuleFileNameHint().DacGetRawUnicode();
if (szPath == NULL)
{
goto NoFileName;
@@ -4198,12 +4198,12 @@ HRESULT DacDbiInterfaceImpl::IsModuleMapped(VMPTR_Module pModule, OUT BOOL *isMo
EX_TRY
{
- PTR_PEFile pPEFile = pTargetModule->GetFile();
- _ASSERTE(pPEFile != NULL);
+ PTR_PEAssembly pPEAssembly = pTargetModule->GetPEAssembly();
+ _ASSERTE(pPEAssembly != NULL);
- if (pPEFile->HasLoadedIL())
+ if (pPEAssembly->HasLoadedPEImage())
{
- *isModuleMapped = pPEFile->GetLoadedIL()->IsMapped();
+ *isModuleMapped = pPEAssembly->GetLoadedLayout()->IsMapped();
hr = S_OK;
}
}
@@ -4296,11 +4296,11 @@ void DacDbiInterfaceImpl::GetMetadata(VMPTR_Module vmModule, TargetBuffer * pTar
}
else
{
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pPEAssembly = pModule->GetPEAssembly();
// For non-dynamic modules, metadata is in the pe-image.
COUNT_T size;
- CORDB_ADDRESS address = PTR_TO_CORDB_ADDRESS(dac_cast(pFile->GetLoadedMetadata(&size)));
+ CORDB_ADDRESS address = PTR_TO_CORDB_ADDRESS(dac_cast(pPEAssembly->GetLoadedMetadata(&size)));
pTargetBuffer->Init(address, (ULONG) size);
}
@@ -4386,9 +4386,9 @@ void DacDbiInterfaceImpl::GetModuleData(VMPTR_Module vmModule, ModuleInfo * pDat
ZeroMemory(pData, sizeof(*pData));
Module * pModule = vmModule.GetDacPtr();
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pPEAssembly = pModule->GetPEAssembly();
- pData->vmPEFile.SetHostPtr(pFile);
+ pData->vmPEAssembly.SetHostPtr(pPEAssembly);
pData->vmAssembly.SetHostPtr(pModule->GetAssembly());
// Is it dynamic?
@@ -4403,15 +4403,15 @@ void DacDbiInterfaceImpl::GetModuleData(VMPTR_Module vmModule, ModuleInfo * pDat
if (!fIsDynamic)
{
COUNT_T size = 0;
- pData->pPEBaseAddress = PTR_TO_TADDR(pFile->GetDebuggerContents(&size));
+ pData->pPEBaseAddress = PTR_TO_TADDR(pPEAssembly->GetDebuggerContents(&size));
pData->nPESize = (ULONG) size;
}
// In-memory is determined by whether the module has a filename.
pData->fInMemory = FALSE;
- if (pFile != NULL)
+ if (pPEAssembly != NULL)
{
- pData->fInMemory = pFile->GetPath().IsEmpty();
+ pData->fInMemory = pPEAssembly->GetPath().IsEmpty();
}
}
@@ -7318,13 +7318,13 @@ void DacDbiInterfaceImpl::GetGCHeapInformation(COR_HEAPINFO * pHeapInfo)
}
-HRESULT DacDbiInterfaceImpl::GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW)
+HRESULT DacDbiInterfaceImpl::GetPEFileMDInternalRW(VMPTR_PEAssembly vmPEAssembly, OUT TADDR* pAddrMDInternalRW)
{
DD_ENTER_MAY_THROW;
if (pAddrMDInternalRW == NULL)
return E_INVALIDARG;
- PEFile * pPEFile = vmPEFile.GetDacPtr();
- *pAddrMDInternalRW = pPEFile->GetMDInternalRWAddress();
+ PEAssembly * pPEAssembly = vmPEAssembly.GetDacPtr();
+ *pAddrMDInternalRW = pPEAssembly->GetMDInternalRWAddress();
return S_OK;
}
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h
index 3088ed007a717..e484a28008b0c 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.h
+++ b/src/coreclr/debug/daccess/dacdbiimpl.h
@@ -53,7 +53,7 @@ class DacDbiInterfaceImpl :
// Overridden from ClrDataAccess. Gets an internal metadata importer for the file.
virtual IMDInternalImport* GetMDImport(
- const PEFile* pPEFile,
+ const PEAssembly* pPEAssembly,
const ReflectionModule * pReflectionModule,
bool fThrowEx);
@@ -149,7 +149,7 @@ class DacDbiInterfaceImpl :
HRESULT GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout);
HRESULT GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout);
void GetGCHeapInformation(COR_HEAPINFO * pHeapInfo);
- HRESULT GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW);
+ HRESULT GetPEFileMDInternalRW(VMPTR_PEAssembly vmPEAssembly, OUT TADDR* pAddrMDInternalRW);
HRESULT GetReJitInfo(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ReJitInfo* pReJitInfo);
HRESULT GetActiveRejitILCodeVersionNode(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ILCodeVersionNode* pVmILCodeVersionNode);
HRESULT GetReJitInfo(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeStartAddress, OUT VMPTR_ReJitInfo* pReJitInfo);
@@ -952,15 +952,15 @@ class DacDbiInterfaceImpl :
IMetaDataLookup * m_pMetaDataLookup;
- // Metadata lookups is just a property on the PEFile in the normal builds,
+ // Metadata lookups is just a property on the PEAssembly in the normal builds,
// and so VM code tends to access the same metadata importer many times in a row.
// Cache the most-recently used to avoid excessive redundant lookups.
- // PEFile of Cached Importer. Invalidated between Flush calls. If this is Non-null,
+ // PEAssembly of Cached Importer. Invalidated between Flush calls. If this is Non-null,
// then the importer is m_pCachedImporter, and we can avoid using IMetaDataLookup
- VMPTR_PEFile m_pCachedPEFile;
+ VMPTR_PEAssembly m_pCachedPEAssembly;
- // Value of cached importer, corresponds with m_pCachedPEFile.
+ // Value of cached importer, corresponds with m_pCachedPEAssembly.
IMDInternalImport * m_pCachedImporter;
// Value of cached hijack function list, corresponds to g_pDebugger->m_rgHijackFunction
@@ -1104,13 +1104,13 @@ class DacDbiInterfaceImpl :
public:
// APIs for picking up the info needed for a debugger to look up an ngen image or IL image
// from it's search path.
- bool GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
+ bool GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
bool &isNGEN,
IStringHolder* pStrFilename);
- bool GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
+ bool GetILImageInfoFromNgenPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
IStringHolder* pStrFilename);
diff --git a/src/coreclr/debug/daccess/dacfn.cpp b/src/coreclr/debug/daccess/dacfn.cpp
index c8ac208d6352c..e1b83aba17e20 100644
--- a/src/coreclr/debug/daccess/dacfn.cpp
+++ b/src/coreclr/debug/daccess/dacfn.cpp
@@ -1304,7 +1304,7 @@ DacSetMethodDescEnumerated(LPCVOID pMD)
// This gets called from DAC-ized code in the VM.
IMDInternalImport*
-DacGetMDImport(const PEFile* peFile, bool throwEx)
+DacGetMDImport(const PEAssembly* pPEAssembly, bool throwEx)
{
if (!g_dacImpl)
{
@@ -1312,7 +1312,7 @@ DacGetMDImport(const PEFile* peFile, bool throwEx)
UNREACHABLE();
}
- return g_dacImpl->GetMDImport(peFile, throwEx);
+ return g_dacImpl->GetMDImport(pPEAssembly, throwEx);
}
IMDInternalImport*
diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h
index 62d99ec574929..84d560e73ec03 100644
--- a/src/coreclr/debug/daccess/dacimpl.h
+++ b/src/coreclr/debug/daccess/dacimpl.h
@@ -132,7 +132,7 @@ class ReflectionModule;
struct DAC_MD_IMPORT
{
DAC_MD_IMPORT* next; // list link field
- TADDR peFile; // a TADDR for a PEFile* or a ReflectionModule*
+ TADDR peFile; // a TADDR for a PEAssembly* or a ReflectionModule*
IMDInternalImport* impl; // Associated metadata interface
bool isAlternate; // for NGEN images set to true if the metadata corresponds to the IL image
@@ -151,7 +151,7 @@ struct DAC_MD_IMPORT
// This class maintains a cache of IMDInternalImport* and their corresponding
-// source (a PEFile* or a ReflectionModule*), as a singly-linked list of
+// source (a PEAssembly* or a ReflectionModule*), as a singly-linked list of
// DAC_MD_IMPORT nodes. The cache is flushed whenever the process state changes
// by calling its Flush() member function.
class MDImportsCache
@@ -1352,18 +1352,18 @@ class ClrDataAccess
JITNotification* GetHostJitNotificationTable();
GcNotification* GetHostGcNotificationTable();
- void* GetMetaDataFromHost(PEFile* peFile,
+ void* GetMetaDataFromHost(PEAssembly* pPEAssembly,
bool* isAlternate);
virtual
- interface IMDInternalImport* GetMDImport(const PEFile* peFile,
+ interface IMDInternalImport* GetMDImport(const PEAssembly* pPEAssembly,
const ReflectionModule* reflectionModule,
bool throwEx);
- interface IMDInternalImport* GetMDImport(const PEFile* peFile,
+ interface IMDInternalImport* GetMDImport(const PEAssembly* pPEAssembly,
bool throwEx)
{
- return GetMDImport(peFile, NULL, throwEx);
+ return GetMDImport(pPEAssembly, NULL, throwEx);
}
interface IMDInternalImport* GetMDImport(const ReflectionModule* reflectionModule,
@@ -1501,7 +1501,7 @@ class ClrDataAccess
public:
// APIs for picking up the info needed for a debugger to look up an ngen image or IL image
// from it's search path.
- static bool GetMetaDataFileInfoFromPEFile(PEFile *pPEFile,
+ static bool GetMetaDataFileInfoFromPEFile(PEAssembly *pPEAssembly,
DWORD &dwImageTimestamp,
DWORD &dwImageSize,
DWORD &dwDataSize,
@@ -1510,7 +1510,7 @@ class ClrDataAccess
__out_ecount(cchFilePath) LPWSTR wszFilePath,
DWORD cchFilePath);
- static bool GetILImageInfoFromNgenPEFile(PEFile *peFile,
+ static bool GetILImageInfoFromNgenPEFile(PEAssembly *pPEAssembly,
DWORD &dwTimeStamp,
DWORD &dwSize,
__out_ecount(cchPath) LPWSTR wszPath,
diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp
index f956151f7ce8e..712f0b35c73f0 100644
--- a/src/coreclr/debug/daccess/enummem.cpp
+++ b/src/coreclr/debug/daccess/enummem.cpp
@@ -67,7 +67,7 @@ HRESULT ClrDataAccess::EnumMemCollectImages()
ProcessModIter modIter;
Module* modDef = NULL;
HRESULT status = S_OK;
- PEFile *file;
+ PEAssembly *assembly;
TADDR pStartAddr = 0;
ULONG32 ulSize = 0;
ULONG32 ulSizeBlock;
@@ -84,7 +84,7 @@ HRESULT ClrDataAccess::EnumMemCollectImages()
EX_TRY
{
ulSize = 0;
- file = modDef->GetFile();
+ assembly = modDef->GetPEAssembly();
// We want to save any in-memory images. These show up like mapped files
// and so would not be in a heap dump by default. Technically it's not clear we
@@ -92,13 +92,11 @@ HRESULT ClrDataAccess::EnumMemCollectImages()
// after-the-fact. But in-memory modules may be harder to track down at debug time
// and people may have come to rely on this - so we'll include them for now.
if (
- file->GetPath().IsEmpty() && // is in-memory
- file->HasMetadata() && // skip resource assemblies
- file->IsLoaded(FALSE) && // skip files not yet loaded
- !file->IsDynamic()) // skip dynamic (GetLoadedIL asserts anyway)
+ assembly->GetPath().IsEmpty() && // is in-memory
+ assembly->HasLoadedPEImage()) // skip files not yet loaded or Dynamic
{
- pStartAddr = PTR_TO_TADDR(file->GetLoadedIL()->GetBase());
- ulSize = file->GetLoadedIL()->GetSize();
+ pStartAddr = PTR_TO_TADDR(assembly->GetLoadedLayout()->GetBase());
+ ulSize = assembly->GetLoadedLayout()->GetSize();
}
// memory are mapped in in GetOsPageSize() size.
@@ -609,7 +607,7 @@ HRESULT ClrDataAccess::EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags)
Module* modDef;
TADDR base;
ULONG32 length;
- PEFile *file;
+ PEAssembly* assembly;
TSIZE_T cbMemoryReported = m_cbMemoryReported;
//
@@ -635,8 +633,8 @@ HRESULT ClrDataAccess::EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags)
// To enable a debugger to check on whether a module is an NI or IL image, they need
// the DOS header, PE headers, and IMAGE_COR20_HEADER for the Flags member.
// We expose no API today to find this out.
- PTR_PEFile pPEFile = modDef->GetFile();
- PEImage * pILImage = pPEFile->GetILimage();
+ PTR_PEAssembly pPEAssembly = modDef->GetPEAssembly();
+ PEImage * pILImage = pPEAssembly->GetPEImage();
// Implicitly gets the COR header.
if ((pILImage) && (pILImage->HasLoadedLayout()))
@@ -649,9 +647,9 @@ HRESULT ClrDataAccess::EnumMemDumpModuleList(CLRDataEnumMemoryFlags flags)
EX_TRY
{
- file = modDef->GetFile();
- base = PTR_TO_TADDR(file->GetLoadedImageContents(&length));
- file->EnumMemoryRegions(flags);
+ assembly = modDef->GetPEAssembly();
+ base = PTR_TO_TADDR(assembly->GetLoadedImageContents(&length));
+ assembly->EnumMemoryRegions(flags);
}
EX_CATCH
{
@@ -1599,6 +1597,7 @@ HRESULT ClrDataAccess::EnumMemoryRegionsWorkerSkinny(IN CLRDataEnumMemoryFlags f
//
// collect CLR static
CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRStatic(flags); )
+ CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemCLRHeapCrticalStatic(flags); );
// Dump AppDomain-specific info needed for MiniDumpNormal.
CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED( status = EnumMemDumpAppDomainInfo(flags); )
diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp
index 0048e43c3d018..8d6ae0b3bb85f 100644
--- a/src/coreclr/debug/daccess/request.cpp
+++ b/src/coreclr/debug/daccess/request.cpp
@@ -1506,8 +1506,8 @@ ClrDataAccess::GetObjectClassName(CLRDATA_ADDRESS obj, unsigned int count, __out
{
// There is a case where metadata was unloaded and the AppendType call will fail.
// This is when an AppDomain has been unloaded but not yet collected.
- PEFile *pPEFile = mt->GetModule()->GetFile();
- if (pPEFile->GetILimage() == NULL)
+ PEAssembly *pPEAssembly = mt->GetModule()->GetPEAssembly();
+ if (pPEAssembly->GetPEImage() == NULL)
{
if (pNeeded)
*pNeeded = 16;
@@ -1645,14 +1645,14 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module
ZeroMemory(ModuleData,sizeof(DacpModuleData));
ModuleData->Address = addr;
- ModuleData->File = HOST_CDADDR(pModule->GetFile());
+ ModuleData->PEAssembly = HOST_CDADDR(pModule->GetPEAssembly());
COUNT_T metadataSize = 0;
- if (!pModule->GetFile()->IsDynamic())
+ if (!pModule->GetPEAssembly()->IsDynamic())
{
- ModuleData->ilBase = (CLRDATA_ADDRESS)(ULONG_PTR) pModule->GetFile()->GetIJWBase();
+ ModuleData->ilBase = (CLRDATA_ADDRESS)(ULONG_PTR) pModule->GetPEAssembly()->GetIJWBase();
}
- ModuleData->metadataStart = (CLRDATA_ADDRESS)dac_cast(pModule->GetFile()->GetLoadedMetadata(&metadataSize));
+ ModuleData->metadataStart = (CLRDATA_ADDRESS)dac_cast(pModule->GetPEAssembly()->GetLoadedMetadata(&metadataSize));
ModuleData->metadataSize = (SIZE_T) metadataSize;
ModuleData->bIsReflection = pModule->IsReflection();
@@ -1770,8 +1770,8 @@ ClrDataAccess::GetMethodTableName(CLRDATA_ADDRESS mt, unsigned int count, __out_
{
// There is a case where metadata was unloaded and the AppendType call will fail.
// This is when an AppDomain has been unloaded but not yet collected.
- PEFile *pPEFile = pMT->GetModule()->GetFile();
- if (pPEFile->GetILimage() == NULL)
+ PEAssembly *pPEAssembly = pMT->GetModule()->GetPEAssembly();
+ if (pPEAssembly->GetPEImage() == NULL)
{
if (pNeeded)
*pNeeded = 16;
@@ -2053,19 +2053,18 @@ ClrDataAccess::GetPEFileName(CLRDATA_ADDRESS addr, unsigned int count, __out_z _
return E_INVALIDARG;
SOSDacEnter();
- PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
+ PEAssembly* pPEAssembly = PTR_PEAssembly(TO_TADDR(addr));
// Turn from bytes to wide characters
- if (!pPEFile->GetPath().IsEmpty())
+ if (!pPEAssembly->GetPath().IsEmpty())
{
- if (!pPEFile->GetPath().DacGetUnicode(count, fileName, pNeeded))
+ if (!pPEAssembly->GetPath().DacGetUnicode(count, fileName, pNeeded))
hr = E_FAIL;
}
- else if (!pPEFile->IsDynamic())
+ else if (!pPEAssembly->IsDynamic())
{
- PEAssembly *pAssembly = pPEFile->GetAssembly();
StackSString displayName;
- pAssembly->GetDisplayName(displayName, 0);
+ pPEAssembly->GetDisplayName(displayName, 0);
if (displayName.IsEmpty())
{
@@ -2112,11 +2111,11 @@ ClrDataAccess::GetPEFileBase(CLRDATA_ADDRESS addr, CLRDATA_ADDRESS *base)
SOSDacEnter();
- PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
+ PEAssembly* pPEAssembly = PTR_PEAssembly(TO_TADDR(addr));
// More fields later?
- if (!pPEFile->IsDynamic())
- *base = TO_CDADDR(pPEFile->GetIJWBase());
+ if (!pPEAssembly->IsDynamic())
+ *base = TO_CDADDR(pPEAssembly->GetIJWBase());
else
*base = NULL;
@@ -4768,8 +4767,8 @@ HRESULT ClrDataAccess::GetAssemblyLoadContext(CLRDATA_ADDRESS methodTable, CLRDA
PTR_MethodTable pMT = PTR_MethodTable(CLRDATA_ADDRESS_TO_TADDR(methodTable));
PTR_Module pModule = pMT->GetModule();
- PTR_PEFile pPEFile = pModule->GetFile();
- PTR_AssemblyBinder pBinder = pPEFile->GetAssemblyBinder();
+ PTR_PEAssembly pPEAssembly = pModule->GetPEAssembly();
+ PTR_AssemblyBinder pBinder = pPEAssembly->GetAssemblyBinder();
INT_PTR managedAssemblyLoadContextHandle = pBinder->GetManagedAssemblyLoadContext();
diff --git a/src/coreclr/debug/daccess/request_svr.cpp b/src/coreclr/debug/daccess/request_svr.cpp
index 4528afe27dab1..b2c09a92c625e 100644
--- a/src/coreclr/debug/daccess/request_svr.cpp
+++ b/src/coreclr/debug/daccess/request_svr.cpp
@@ -122,8 +122,11 @@ ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *
detailsData->lowest_address = PTR_CDADDR(g_lowest_address);
detailsData->highest_address = PTR_CDADDR(g_highest_address);
- detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
-
+ detailsData->current_c_gc_state = c_gc_state_free;
+ if (g_gcDacGlobals->current_c_gc_state != NULL)
+ {
+ detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
+ }
// now get information specific to this heap (server mode gives us several heaps; we're getting
// information about only one of them.
detailsData->alloc_allocated = (CLRDATA_ADDRESS)pHeap->alloc_allocated;
diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp
index 8989977880e2e..5c8c3d0152dcf 100644
--- a/src/coreclr/debug/daccess/task.cpp
+++ b/src/coreclr/debug/daccess/task.cpp
@@ -2414,12 +2414,12 @@ ClrDataModule::GetFileName(
{
COUNT_T _nameLen;
- // Try to get the file name through GetPath.
- // If the returned name is empty, then try to get the guessed module file name.
- // The guessed file name is propogated from metadata's module name.
+ // Try to get the assembly name through GetPath.
+ // If the returned name is empty, then try to get the guessed module assembly name.
+ // The guessed assembly name is propogated from metadata's module name.
//
- if ((m_module->GetFile()->GetPath().DacGetUnicode(bufLen, name, &_nameLen) && name[0])||
- (m_module->GetFile()->GetModuleFileNameHint().DacGetUnicode(bufLen, name, &_nameLen) && name[0]))
+ if ((m_module->GetPEAssembly()->GetPath().DacGetUnicode(bufLen, name, &_nameLen) && name[0])||
+ (m_module->GetPEAssembly()->GetModuleFileNameHint().DacGetUnicode(bufLen, name, &_nameLen) && name[0]))
{
if (nameLen)
{
@@ -2455,19 +2455,11 @@ ClrDataModule::GetVersionId(
EX_TRY
{
- if (!m_module->GetFile()->HasMetadata())
+ GUID mdVid;
+ status = m_module->GetMDImport()->GetScopeProps(NULL, &mdVid);
+ if (SUCCEEDED(status))
{
- status = E_NOINTERFACE;
- }
- else
- {
- GUID mdVid;
-
- status = m_module->GetMDImport()->GetScopeProps(NULL, &mdVid);
- if (SUCCEEDED(status))
- {
- *vid = mdVid;
- }
+ *vid = mdVid;
}
}
EX_CATCH
@@ -2499,10 +2491,7 @@ ClrDataModule::GetFlags(
{
(*flags) |= CLRDATA_MODULE_IS_DYNAMIC;
}
- if (m_module->IsIStream())
- {
- (*flags) |= CLRDATA_MODULE_IS_MEMORY_STREAM;
- }
+
PTR_Assembly pAssembly = m_module->GetAssembly();
PTR_BaseDomain pBaseDomain = pAssembly->GetDomain();
if (pBaseDomain->IsAppDomain())
@@ -2568,8 +2557,8 @@ ClrDataModule::StartEnumExtents(
{
if (!m_setExtents)
{
- PEFile* file = m_module->GetFile();
- if (!file)
+ PEAssembly* assembly = m_module->GetPEAssembly();
+ if (!assembly)
{
*handle = 0;
status = E_INVALIDARG;
@@ -2578,10 +2567,10 @@ ClrDataModule::StartEnumExtents(
CLRDATA_MODULE_EXTENT* extent = m_extents;
- if (file->GetLoadedImageContents() != NULL)
+ if (assembly->GetLoadedImageContents() != NULL)
{
extent->base =
- TO_CDADDR( PTR_TO_TADDR(file->GetLoadedImageContents(&extent->length)) );
+ TO_CDADDR( PTR_TO_TADDR(assembly->GetLoadedImageContents(&extent->length)) );
extent->type = CLRDATA_MODULE_PE_FILE;
extent++;
}
@@ -2723,23 +2712,23 @@ ClrDataModule::RequestGetModuleData(
ZeroMemory(outGMD, sizeof(DacpGetModuleData));
Module* pModule = GetModule();
- PEFile *pPEFile = pModule->GetFile();
+ PEAssembly *pPEAssembly = pModule->GetPEAssembly();
- outGMD->PEFile = TO_CDADDR(PTR_HOST_TO_TADDR(pPEFile));
+ outGMD->PEAssembly = TO_CDADDR(PTR_HOST_TO_TADDR(pPEAssembly));
outGMD->IsDynamic = pModule->IsReflection();
- if (pPEFile != NULL)
+ if (pPEAssembly != NULL)
{
- outGMD->IsInMemory = pPEFile->GetPath().IsEmpty();
+ outGMD->IsInMemory = pPEAssembly->GetPath().IsEmpty();
COUNT_T peSize;
- outGMD->LoadedPEAddress = TO_CDADDR(PTR_TO_TADDR(pPEFile->GetLoadedImageContents(&peSize)));
+ outGMD->LoadedPEAddress = TO_CDADDR(PTR_TO_TADDR(pPEAssembly->GetLoadedImageContents(&peSize)));
outGMD->LoadedPESize = (ULONG64)peSize;
- // Can not get the file layout for a dynamic module
+ // Can not get the assembly layout for a dynamic module
if (!outGMD->IsDynamic)
{
- outGMD->IsFileLayout = pPEFile->GetLoaded()->IsFlat();
+ outGMD->IsFileLayout = pPEAssembly->GetLoadedLayout()->IsFlat();
}
}
@@ -2876,17 +2865,10 @@ ClrDataModule::GetMdInterface(PVOID* retIface)
{
if (m_mdImport == NULL)
{
- if (!m_module->GetFile()->HasMetadata())
- {
- status = E_NOINTERFACE;
- goto Exit;
- }
-
//
// Make sure internal MD is in RW format.
//
IMDInternalImport* rwMd;
-
status = ConvertMDInternalImport(m_module->GetMDImport(), &rwMd);
if (FAILED(status))
{
diff --git a/src/coreclr/debug/di/module.cpp b/src/coreclr/debug/di/module.cpp
index e662f8cb86e24..b48e12afc96be 100644
--- a/src/coreclr/debug/di/module.cpp
+++ b/src/coreclr/debug/di/module.cpp
@@ -82,7 +82,7 @@ CordbModule::CordbModule(
m_fDynamic = modInfo.fIsDynamic;
m_fInMemory = modInfo.fInMemory;
- m_vmPEFile = modInfo.vmPEFile;
+ m_vmPEFile = modInfo.vmPEAssembly;
if (!vmDomainFile.IsNull())
{
@@ -268,13 +268,13 @@ IDacDbiInterface::SymbolFormat CordbModule::GetInMemorySymbolStream(IStream ** p
// Accessor for PE file.
//
// Returns:
-// VMPTR_PEFile for this module. Should always be non-null
+// VMPTR_PEAssembly for this module. Should always be non-null
//
// Notes:
// A main usage of this is to find the proper internal MetaData importer.
-// DACized code needs to map from PEFile --> IMDInternalImport.
+// DACized code needs to map from PEAssembly --> IMDInternalImport.
//
-VMPTR_PEFile CordbModule::GetPEFile()
+VMPTR_PEAssembly CordbModule::GetPEFile()
{
return m_vmPEFile;
}
diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp
index 134e3dbab4c96..c6c16d0700a85 100644
--- a/src/coreclr/debug/di/process.cpp
+++ b/src/coreclr/debug/di/process.cpp
@@ -290,10 +290,10 @@ static inline DWORD CordbGetWaitTimeout()
//----------------------------------------------------------------------------
// Implementation of IDacDbiInterface::IMetaDataLookup.
-// lookup Internal Metadata Importer keyed by PEFile
+// lookup Internal Metadata Importer keyed by PEAssembly
// isILMetaDataForNGENImage is true iff the IMDInternalImport returned represents a pointer to
// metadata from an IL image when the module was an ngen'ed image.
-IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &isILMetaDataForNGENImage)
+IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEAssembly vmPEAssembly, bool &isILMetaDataForNGENImage)
{
INTERNAL_DAC_CALLBACK(this);
@@ -312,7 +312,7 @@ IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &is
pModule != NULL;
pModule = pAppDomain->m_modules.FindNext(&hashFindModule))
{
- if (pModule->GetPEFile() == vmPEFile)
+ if (pModule->GetPEFile() == vmPEAssembly)
{
pMDII = NULL;
ALLOW_DATATARGET_MISSING_MEMORY(
@@ -341,7 +341,7 @@ IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &is
pModule != NULL;
pModule = pAppDomain->m_modules.FindNext(&hashFindModule))
{
- if (pModule->GetPEFile() == vmPEFile)
+ if (pModule->GetPEFile() == vmPEAssembly)
{
pMDII = NULL;
ALLOW_DATATARGET_MISSING_MEMORY(
@@ -354,7 +354,7 @@ IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &is
// debugger if it can find the metadata elsewhere.
// If this was live debugging, we should have just gotten the memory contents.
// Thus this code is for dump debugging, when you don't have the metadata in the dump.
- pMDII = LookupMetaDataFromDebugger(vmPEFile, isILMetaDataForNGENImage, pModule);
+ pMDII = LookupMetaDataFromDebugger(vmPEAssembly, isILMetaDataForNGENImage, pModule);
}
return pMDII;
}
@@ -366,7 +366,7 @@ IMDInternalImport * CordbProcess::LookupMetaData(VMPTR_PEFile vmPEFile, bool &is
IMDInternalImport * CordbProcess::LookupMetaDataFromDebugger(
- VMPTR_PEFile vmPEFile,
+ VMPTR_PEAssembly vmPEAssembly,
bool &isILMetaDataForNGENImage,
CordbModule * pModule)
{
@@ -377,7 +377,7 @@ IMDInternalImport * CordbProcess::LookupMetaDataFromDebugger(
IMDInternalImport * pMDII = NULL;
// First, see if the debugger can locate the exact metadata we want.
- if (this->GetDAC()->GetMetaDataFileInfoFromPEFile(vmPEFile, dwImageTimeStamp, dwImageSize, isNGEN, &filePath))
+ if (this->GetDAC()->GetMetaDataFileInfoFromPEFile(vmPEAssembly, dwImageTimeStamp, dwImageSize, isNGEN, &filePath))
{
_ASSERTE(filePath.IsSet());
@@ -408,7 +408,7 @@ IMDInternalImport * CordbProcess::LookupMetaDataFromDebugger(
filePath.Clear();
if ((pMDII == NULL) &&
(isNGEN) &&
- (this->GetDAC()->GetILImageInfoFromNgenPEFile(vmPEFile, dwImageTimeStamp, dwImageSize, &filePath)))
+ (this->GetDAC()->GetILImageInfoFromNgenPEFile(vmPEAssembly, dwImageTimeStamp, dwImageSize, &filePath)))
{
_ASSERTE(filePath.IsSet());
@@ -496,7 +496,7 @@ IMDInternalImport * CordbProcess::LookupMetaDataFromDebuggerForSingleFile(
if (SUCCEEDED(hr))
{
// While we're successfully returning a metadata reader, remember that there's
- // absolutely no guarantee this metadata is an exact match for the vmPEFile.
+ // absolutely no guarantee this metadata is an exact match for the vmPEAssembly.
// The debugger could literally send us back a path to any managed file with
// metadata content that is readable and we'll 'succeed'.
// For now, this is by-design. A debugger should be allowed to decide if it wants
diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h
index 7d257f6556e52..1baa6a9f24afd 100644
--- a/src/coreclr/debug/di/rspriv.h
+++ b/src/coreclr/debug/di/rspriv.h
@@ -2975,10 +2975,10 @@ class CordbProcess :
//-----------------------------------------------------------
// IMetaDataLookup
// -----------------------------------------------------------
- IMDInternalImport * LookupMetaData(VMPTR_PEFile vmPEFile, bool &isILMetaDataForNGENImage);
+ IMDInternalImport * LookupMetaData(VMPTR_PEAssembly vmPEAssembly, bool &isILMetaDataForNGENImage);
// Helper functions for LookupMetaData implementation
- IMDInternalImport * LookupMetaDataFromDebugger(VMPTR_PEFile vmPEFile,
+ IMDInternalImport * LookupMetaDataFromDebugger(VMPTR_PEAssembly vmPEAssembly,
bool &isILMetaDataForNGENImage,
CordbModule * pModule);
@@ -4368,7 +4368,7 @@ class CordbModule : public CordbBase,
IDacDbiInterface::SymbolFormat GetInMemorySymbolStream(IStream ** ppStream);
// accessor for PE file
- VMPTR_PEFile GetPEFile();
+ VMPTR_PEAssembly GetPEFile();
IMetaDataImport * GetMetaDataImporter();
@@ -4419,9 +4419,9 @@ class CordbModule : public CordbBase,
// "Global" class for this module. Global functions + vars exist in this class.
RSSmartPtr m_pClass;
- // Handle to PEFile, useful for metadata lookups.
+ // Handle to PEAssembly, useful for metadata lookups.
// this should always be non-null.
- VMPTR_PEFile m_vmPEFile;
+ VMPTR_PEAssembly m_vmPEFile;
// Public metadata importer. This is lazily initialized and accessed from code:GetMetaDataImporter
diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp
index 2a8f565d686eb..0f61f8d36c78e 100644
--- a/src/coreclr/debug/ee/debugger.cpp
+++ b/src/coreclr/debug/ee/debugger.cpp
@@ -9537,21 +9537,6 @@ void Debugger::LoadModule(Module* pRuntimeModule,
SENDIPCEVENT_END;
- // need to update pdb stream for SQL passed in pdb stream
- // regardless attach or not.
- //
- if (pRuntimeModule->IsIStream())
- {
- // Just ignore failures. Caller was just sending a debug event and we don't
- // want that to interop non-debugging functionality.
- HRESULT hr = S_OK;
- EX_TRY
- {
- SendUpdateModuleSymsEventAndBlock(pRuntimeModule, pAppDomain);
- }
- EX_CATCH_HRESULT(hr);
- }
-
// Now that we're done with the load module event, can no longer change Jit flags.
module->SetCanChangeJitFlags(false);
}
@@ -9710,7 +9695,7 @@ void Debugger::UnloadModule(Module* pRuntimeModule,
STRESS_LOG6(LF_CORDB, LL_INFO10000,
"D::UM: Unloading RTMod:%#08x (DomFile: %#08x, IsISStream:%#08x); DMod:%#08x(RTMod:%#08x DomFile: %#08x)\n",
- pRuntimeModule, pRuntimeModule->GetDomainFile(), pRuntimeModule->IsIStream(),
+ pRuntimeModule, pRuntimeModule->GetDomainFile(), false,
module, module->GetRuntimeModule(), module->GetDomainFile());
// Note: the appdomain the module was loaded in must match the appdomain we're unloading it from. If it doesn't,
diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h
index 6696da0cbbbb0..0bda865bd0f59 100644
--- a/src/coreclr/debug/inc/dacdbiinterface.h
+++ b/src/coreclr/debug/inc/dacdbiinterface.h
@@ -521,7 +521,7 @@ class IDacDbiInterface
//
// For dynamic modules, the CLR will eagerly serialize the metadata at "debuggable" points. This
// could be after each type is loaded; or after a bulk update.
- // For non-dynamic modules (both in-memory and file-based), the metadata exists in the PEFile's image.
+ // For non-dynamic modules (both in-memory and file-based), the metadata exists in the PEAssembly's image.
//
// Failure cases:
// This should succeed in normal, live-debugging scenarios. However, common failure paths here would be:
@@ -2379,14 +2379,14 @@ class IDacDbiInterface
CLR_DEBUGGING_PROCESS_FLAGS GetAttachStateFlags() = 0;
virtual
- bool GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
+ bool GetMetaDataFileInfoFromPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD & dwTimeStamp,
DWORD & dwImageSize,
bool & isNGEN,
IStringHolder* pStrFilename) = 0;
virtual
- bool GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
+ bool GetILImageInfoFromNgenPEFile(VMPTR_PEAssembly vmPEAssembly,
DWORD & dwTimeStamp,
DWORD & dwSize,
IStringHolder* pStrFilename) = 0;
@@ -2512,17 +2512,17 @@ class IDacDbiInterface
virtual
void GetGCHeapInformation(OUT COR_HEAPINFO * pHeapInfo) = 0;
- // If a PEFile has an RW capable IMDInternalImport, this returns the address of the MDInternalRW
+ // If a PEAssembly has an RW capable IMDInternalImport, this returns the address of the MDInternalRW
// object which implements it.
//
//
// Arguments:
- // vmPEFile - target PEFile to get metadata MDInternalRW for.
- // pAddrMDInternalRW - If a PEFile has an RW capable IMDInternalImport, this will be set to the address
+ // vmPEAssembly - target PEAssembly to get metadata MDInternalRW for.
+ // pAddrMDInternalRW - If a PEAssembly has an RW capable IMDInternalImport, this will be set to the address
// of the MDInternalRW object which implements it. Otherwise it will be NULL.
//
virtual
- HRESULT GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW) = 0;
+ HRESULT GetPEFileMDInternalRW(VMPTR_PEAssembly vmPEAssembly, OUT TADDR* pAddrMDInternalRW) = 0;
// DEPRECATED - use GetActiveRejitILCodeVersionNode
// Retrieves the active ReJitInfo for a given module/methodDef, if it exists.
@@ -2814,7 +2814,7 @@ class IDacDbiInterface
{
public:
//
- // Lookup a metadata importer via PEFile.
+ // Lookup a metadata importer via PEAssembly.
//
// Returns:
// A IMDInternalImport used by dac-ized VM code. The object is NOT addref-ed. See lifespan notes below.
@@ -2822,7 +2822,7 @@ class IDacDbiInterface
// Throws on exceptional circumstances (eg, detects the debuggee is corrupted).
//
// Notes:
- // IMDInternalImport is a property of PEFile. The DAC-ized code uses it as a weak reference,
+ // IMDInternalImport is a property of PEAssembly. The DAC-ized code uses it as a weak reference,
// and so we avoid doing an AddRef() here because that would mean we need to add Release() calls
// in DAC-only paths.
// The metadata importers are not DAC-ized, and thus we have a local copy in the host.
@@ -2837,7 +2837,7 @@ class IDacDbiInterface
// - the reference count of the returned object is not adjusted.
//
virtual
- IMDInternalImport * LookupMetaData(VMPTR_PEFile addressPEFile, bool &isILMetaDataForNGENImage) = 0;
+ IMDInternalImport * LookupMetaData(VMPTR_PEAssembly addressPEAssembly, bool &isILMetaDataForNGENImage) = 0;
};
}; // end IDacDbiInterface
diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h
index 19c788edb297f..5e02a68a792c9 100644
--- a/src/coreclr/debug/inc/dacdbistructures.h
+++ b/src/coreclr/debug/inc/dacdbistructures.h
@@ -186,10 +186,10 @@ struct MSLAYOUT ModuleInfo
// (such as for a dynamic module that's not persisted to disk).
CORDB_ADDRESS pPEBaseAddress;
- // The PEFile associated with the module. Every module (even non-file-based ones) has a PEFile.
+ // The PEAssembly associated with the module. Every module (even non-file-based ones) has a PEAssembly.
// This is critical because DAC may ask for a metadata importer via PE-file.
- // a PEFile may have 1 or more PEImage child objects (1 for IL, 1 for native image, etc)
- VMPTR_PEFile vmPEFile;
+ // a PEAssembly may have 1 or more PEImage child objects (1 for IL, 1 for native image, etc)
+ VMPTR_PEAssembly vmPEAssembly;
// The PE Base address and size of the module. These may be 0 if there is no image
// (such as for a dynamic module that's not persisted to disk).
diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h
index da097631b2f8c..db4a00fca1c86 100644
--- a/src/coreclr/debug/inc/dbgipcevents.h
+++ b/src/coreclr/debug/inc/dbgipcevents.h
@@ -858,7 +858,7 @@ DEFINE_VMPTR(class Module, PTR_Module, VMPTR_Module);
DEFINE_VMPTR(class DomainAssembly, PTR_DomainAssembly, VMPTR_DomainAssembly);
DEFINE_VMPTR(class Assembly, PTR_Assembly, VMPTR_Assembly);
-DEFINE_VMPTR(class PEFile, PTR_PEFile, VMPTR_PEFile);
+DEFINE_VMPTR(class PEAssembly, PTR_PEAssembly, VMPTR_PEAssembly);
DEFINE_VMPTR(class MethodDesc, PTR_MethodDesc, VMPTR_MethodDesc);
DEFINE_VMPTR(class FieldDesc, PTR_FieldDesc, VMPTR_FieldDesc);
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index d041ea52d64d1..221d2dc2be631 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -24,6 +24,10 @@
#define USE_INTROSORT
#endif
+#ifdef DACCESS_COMPILE
+#error this source file should not be compiled with DACCESS_COMPILE!
+#endif //DACCESS_COMPILE
+
// We just needed a simple random number generator for testing.
class gc_rand
{
@@ -398,6 +402,7 @@ VOLATILE(bgc_state) gc_heap::current_bgc_state = bgc_not_in_process;
int gc_heap::gchist_index_per_heap = 0;
gc_heap::gc_history gc_heap::gchist_per_heap[max_history_count];
#endif //MULTIPLE_HEAPS
+#endif //BACKGROUND_GC
void gc_heap::add_to_history_per_heap()
{
@@ -444,8 +449,6 @@ void gc_heap::add_to_history()
#endif //GC_HISTORY && BACKGROUND_GC
}
-#endif //BACKGROUND_GC
-
#ifdef TRACE_GC
BOOL gc_log_on = TRUE;
FILE* gc_log = NULL;
@@ -1242,7 +1245,6 @@ class exclusive_sync
void uoh_alloc_done (uint8_t* obj)
{
-#ifdef BACKGROUND_GC
if (!gc_heap::cm_in_progress)
{
return;
@@ -1256,7 +1258,6 @@ class exclusive_sync
return;
}
}
-#endif //BACKGROUND_GC
}
};
@@ -2973,7 +2974,11 @@ void gc_heap::fire_pevents()
uint32_t count_time_info = (settings.concurrent ? max_bgc_time_type :
(settings.compaction ? max_compact_time_type : max_sweep_time_type));
+#ifdef BACKGROUND_GC
uint64_t* time_info = (settings.concurrent ? bgc_time_info : gc_time_info);
+#else
+ uint64_t* time_info = gc_time_info;
+#endif //BACKGROUND_GC
// We don't want to have to fire the time info as 64-bit integers as there's no need to
// so compress them down to 32-bit ones.
uint32_t* time_info_32 = (uint32_t*)time_info;
@@ -8369,13 +8374,8 @@ void gc_heap::clear_mark_array (uint8_t* from, uint8_t* end, BOOL check_only/*=T
}
assert (end == align_on_mark_word (end));
-#ifdef BACKGROUND_GC
uint8_t* current_lowest_address = background_saved_lowest_address;
uint8_t* current_highest_address = background_saved_highest_address;
-#else
- uint8_t* current_lowest_address = lowest_address;
- uint8_t* current_highest_address = highest_address;
-#endif //BACKGROUND_GC
//there is a possibility of the addresses to be
//outside of the covered range because of a newly allocated
@@ -8518,12 +8518,12 @@ void gc_heap::get_card_table_element_sizes (uint8_t* start, uint8_t* end, size_t
sizes[card_bundle_table_element] = size_card_bundle_of (start, end);
}
#endif //CARD_BUNDLE
-#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#if defined(FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP) && defined (BACKGROUND_GC)
if (gc_can_use_concurrent)
{
sizes[software_write_watch_table_element] = SoftwareWriteWatch::GetTableByteSize(start, end);
}
-#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#endif //FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP && BACKGROUND_GC
sizes[seg_mapping_table_element] = size_seg_mapping_table_of (start, end);
#ifdef BACKGROUND_GC
if (gc_can_use_concurrent)
@@ -8819,12 +8819,12 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end)
#endif
#endif //CARD_BUNDLE
-#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#if defined(FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP) && defined (BACKGROUND_GC)
if (gc_can_use_concurrent)
{
SoftwareWriteWatch::InitializeUntranslatedTable(mem + card_table_element_layout[software_write_watch_table_element], start);
}
-#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#endif //FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP && BACKGROUND_GC
seg_mapping_table = (seg_mapping*)(mem + card_table_element_layout[seg_mapping_table_element]);
seg_mapping_table = (seg_mapping*)((uint8_t*)seg_mapping_table -
@@ -9047,7 +9047,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
}
#endif //BACKGROUND_GC
-#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#if defined(FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP) && defined(BACKGROUND_GC)
if (gc_can_use_concurrent)
{
// The current design of software write watch requires that the runtime is suspended during resize. Suspending
@@ -9097,7 +9097,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
}
}
else
-#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#endif //FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP && BACKGROUND_GC
{
g_gc_card_table = translated_ct;
@@ -9182,6 +9182,7 @@ void gc_heap::copy_brick_card_range (uint8_t* la, uint32_t* old_card_table,
uint32_t* old_ct = &old_card_table[card_word (card_of (la))];
+#ifdef BACKGROUND_GC
if (gc_heap::background_running_p())
{
uint32_t* old_mark_array = card_table_mark_array (old_ct);
@@ -9210,6 +9211,7 @@ void gc_heap::copy_brick_card_range (uint8_t* la, uint32_t* old_card_table,
assert (old_brick_table == 0);
}
}
+#endif //BACKGROUND_GC
// n way merge with all of the card table ever used in between
uint32_t* ct = card_table_next (&card_table[card_word (card_of(lowest_address))]);
@@ -9349,7 +9351,10 @@ BOOL gc_heap::insert_ro_segment (heap_segment* seg)
enter_spin_lock (&gc_heap::gc_lock);
if (!gc_heap::seg_table->ensure_space_for_insert ()
- || (is_bgc_in_progress() && !commit_mark_array_new_seg(__this, seg)))
+#ifdef BACKGROUND_GC
+ || (is_bgc_in_progress() && !commit_mark_array_new_seg(__this, seg))
+#endif //BACKGROUND_GC
+ )
{
leave_spin_lock(&gc_heap::gc_lock);
return FALSE;
@@ -12158,7 +12163,10 @@ void gc_heap::distribute_free_regions()
// if so, put the highest free regions on the decommit list
total_num_free_regions[kind] += num_regions_to_decommit[kind];
- if (background_running_p() ||
+ if (
+#ifdef BACKGROUND_GC
+ background_running_p() ||
+#endif
((total_num_free_regions[kind] + num_huge_region_units_to_consider[kind]) < total_budget_in_region_units[kind]))
{
dprintf (REGIONS_LOG, ("distributing the %Id %s regions deficit",
@@ -12386,6 +12394,7 @@ void gc_heap::update_card_table_bundle()
}
#endif //CARD_BUNDLE
+#ifdef BACKGROUND_GC
// static
void gc_heap::reset_write_watch_for_gc_heap(void* base_address, size_t region_size)
{
@@ -12506,6 +12515,7 @@ void gc_heap::reset_write_watch (BOOL concurrent_p)
}
}
}
+#endif //BACKGROUND_GC
#endif //WRITE_WATCH
@@ -12924,9 +12934,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
if (!g_promoted)
return E_OUTOFMEMORY;
#endif //!USE_REGIONS || _DEBUG
+#ifdef BACKGROUND_GC
g_bpromoted = new (nothrow) size_t [number_of_heaps*16];
if (!g_bpromoted)
return E_OUTOFMEMORY;
+#endif
#ifdef MH_SC_MARK
g_mark_stack_busy = new (nothrow) int[(number_of_heaps+2)*HS_CACHE_LINE_SIZE/sizeof(int)];
@@ -27284,11 +27296,13 @@ uint8_t* gc_heap::find_next_marked (uint8_t* x, uint8_t* end,
#endif //MULTIPLE_HEAPS
)
x = *mark_list_next;
+#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
assert(gc_heap::background_running_p());
bgc_clear_batch_mark_array_bits (old_x, x);
}
+#endif //BACKGROUND_GC
}
else
{
@@ -28615,8 +28629,11 @@ void gc_heap::plan_phase (int condemned_gen_number)
}
}
- if (maxgen_size_inc_p && provisional_mode_triggered &&
- !is_bgc_in_progress())
+ if (maxgen_size_inc_p && provisional_mode_triggered
+#ifdef BACKGROUND_GC
+ && !is_bgc_in_progress()
+#endif //BACKGROUND_GC
+ )
{
pm_trigger_full_gc = true;
dprintf (GTC_LOG, ("in PM: maxgen size inc, doing a sweeping gen1 and trigger NGC2"));
@@ -28741,8 +28758,11 @@ void gc_heap::plan_phase (int condemned_gen_number)
rearrange_uoh_segments ();
}
- if (maxgen_size_inc_p && provisional_mode_triggered &&
- !is_bgc_in_progress())
+ if (maxgen_size_inc_p && provisional_mode_triggered
+#ifdef BACKGROUND_GC
+ && !is_bgc_in_progress()
+#endif //BACKGROUND_GC
+ )
{
pm_trigger_full_gc = true;
dprintf (GTC_LOG, ("in PM: maxgen size inc, doing a sweeping gen1 and trigger NGC2"));
@@ -28790,8 +28810,11 @@ void gc_heap::plan_phase (int condemned_gen_number)
if (!pm_trigger_full_gc && pm_stress_on && provisional_mode_triggered)
{
if ((settings.condemned_generation == (max_generation - 1)) &&
- ((settings.gc_index % 5) == 0) &&
- !is_bgc_in_progress())
+ ((settings.gc_index % 5) == 0)
+#ifdef BACKGROUND_GC
+ && !is_bgc_in_progress()
+#endif //BACKGROUND_GC
+ )
{
pm_trigger_full_gc = true;
}
@@ -38061,9 +38084,13 @@ void gc_heap::init_static_data()
#ifdef MULTIPLE_HEAPS
max (6*1024*1024, min ( Align(soh_segment_size/2), 200*1024*1024));
#else //MULTIPLE_HEAPS
- (gc_can_use_concurrent ?
+ (
+#ifdef BACKGROUND_GC
+ gc_can_use_concurrent ?
6*1024*1024 :
- max (6*1024*1024, min ( Align(soh_segment_size/2), 200*1024*1024)));
+#endif //BACKGROUND_GC
+ max (6*1024*1024, min ( Align(soh_segment_size/2), 200*1024*1024))
+ );
#endif //MULTIPLE_HEAPS
gen0_max_size = max (gen0_min_size, gen0_max_size);
@@ -38094,9 +38121,13 @@ void gc_heap::init_static_data()
#ifdef MULTIPLE_HEAPS
max (6*1024*1024, Align(soh_segment_size/2));
#else //MULTIPLE_HEAPS
- (gc_can_use_concurrent ?
+ (
+#ifdef BACKGROUND_GC
+ gc_can_use_concurrent ?
6*1024*1024 :
- max (6*1024*1024, Align(soh_segment_size/2)));
+#endif //BACKGROUND_GC
+ max (6*1024*1024, Align(soh_segment_size/2))
+ );
#endif //MULTIPLE_HEAPS
size_t gen1_max_size_config = (size_t)GCConfig::GetGCGen1MaxBudget();
@@ -38748,7 +38779,7 @@ void gc_heap::decommit_ephemeral_segment_pages()
dynamic_data* dd0 = dynamic_data_of (0);
- ptrdiff_t desired_allocation = estimate_gen_growth (soh_gen0) +
+ ptrdiff_t desired_allocation = dd_new_allocation (dd0) +
estimate_gen_growth (soh_gen1) +
loh_size_threshold;
@@ -43340,6 +43371,7 @@ unsigned int GCHeap::GetGenerationWithRange (Object* object, uint8_t** ppStart,
}
if (generation == -1)
{
+ generation = max_generation;
*ppStart = heap_segment_mem (hs);
*ppAllocated = *ppReserved = generation_allocation_start (hp->generation_of (max_generation - 1));
}
@@ -44592,6 +44624,8 @@ bool gc_heap::is_pm_ratio_exceeded()
void gc_heap::update_recorded_gen_data (last_recorded_gc_info* gc_info)
{
+ memset (gc_info->gen_info, 0, sizeof (gc_info->gen_info));
+
#ifdef MULTIPLE_HEAPS
for (int i = 0; i < gc_heap::n_heaps; i++)
{
@@ -44685,12 +44719,14 @@ void gc_heap::do_post_gc()
// Now record the gc info.
last_recorded_gc_info* last_gc_info = 0;
+#ifdef BACKGROUND_GC
if (settings.concurrent)
{
last_gc_info = &last_bgc_info[last_bgc_info_index];
assert (last_gc_info->index == settings.gc_index);
}
else
+#endif //BACKGROUND_GC
{
last_gc_info = ((settings.condemned_generation == max_generation) ?
&last_full_blocking_gc_info : &last_ephemeral_gc_info);
@@ -44710,10 +44746,12 @@ void gc_heap::do_post_gc()
uint64_t gc_start_ts = dd_time_clock (dd);
size_t pause_duration = (size_t)(end_gc_time - dd_time_clock (dd));
+#ifdef BACKGROUND_GC
if ((hp->current_bgc_state != bgc_initialized) && (settings.reason != reason_pm_full_gc))
{
pause_duration += (size_t)(gc_start_ts - suspended_start_time);
}
+#endif //BACKGROUND_GC
last_gc_info->pause_durations[0] = pause_duration;
total_suspended_time += pause_duration;
@@ -45072,9 +45110,15 @@ size_t GCHeap::ApproxTotalBytesInUse(BOOL small_heap_only)
// Get small block heap size info
totsize = (pGenGCHeap->alloc_allocated - heap_segment_mem (eph_seg));
heap_segment* seg1 = generation_start_segment (pGenGCHeap->generation_of (max_generation));
- while ((seg1 != eph_seg) && (seg1 != nullptr) && (seg1 != pGenGCHeap->freeable_soh_segment))
+ while ((seg1 != eph_seg) && (seg1 != nullptr)
+#ifdef BACKGROUND_GC
+ && (seg1 != pGenGCHeap->freeable_soh_segment)
+#endif //BACKGROUND_GC
+ )
{
+#ifdef BACKGROUND_GC
if (!heap_segment_decommitted_p (seg1))
+#endif //BACKGROUND_GC
{
totsize += heap_segment_allocated (seg1) -
heap_segment_mem (seg1);
@@ -46349,7 +46393,11 @@ void GCHeap::DiagGetGCSettings(EtwGCSettingsInfo* etw_settings)
etw_settings->gen0_min_budget_from_config = gc_heap::gen0_min_budget_from_config;
etw_settings->gen0_max_budget_from_config = gc_heap::gen0_max_budget_from_config;
etw_settings->high_mem_percent_from_config = gc_heap::high_mem_percent_from_config;
+#ifdef BACKGROUND_GC
etw_settings->concurrent_gc_p = gc_heap::gc_can_use_concurrent;
+#else
+ etw_settings->concurrent_gc_p = false;
+#endif //BACKGROUND_GC
etw_settings->use_large_pages_p = gc_heap::use_large_pages_p;
etw_settings->use_frozen_segments_p = gc_heap::use_frozen_segments_p;
etw_settings->hard_limit_config_p = gc_heap::hard_limit_config_p;
@@ -46662,10 +46710,18 @@ void PopulateDacVars(GcDacVars *gcDacVars)
gcDacVars->generation_size = sizeof(generation);
gcDacVars->total_generation_count = total_generation_count;
gcDacVars->max_gen = &g_max_generation;
+#ifdef BACKGROUND_GC
gcDacVars->current_c_gc_state = const_cast(&gc_heap::current_c_gc_state);
+#else //BACKGROUND_GC
+ gcDacVars->current_c_gc_state = 0;
+#endif //BACKGROUND_GC
#ifndef MULTIPLE_HEAPS
- gcDacVars->mark_array = &gc_heap::mark_array;
gcDacVars->ephemeral_heap_segment = reinterpret_cast(&gc_heap::ephemeral_heap_segment);
+#ifdef BACKGROUND_GC
+ gcDacVars->mark_array = &gc_heap::mark_array;
+ gcDacVars->background_saved_lowest_address = &gc_heap::background_saved_lowest_address;
+ gcDacVars->background_saved_highest_address = &gc_heap::background_saved_highest_address;
+ gcDacVars->next_sweep_obj = &gc_heap::next_sweep_obj;
#ifdef USE_REGIONS
gcDacVars->saved_sweep_ephemeral_seg = 0;
gcDacVars->saved_sweep_ephemeral_start = 0;
@@ -46673,10 +46729,15 @@ void PopulateDacVars(GcDacVars *gcDacVars)
gcDacVars->saved_sweep_ephemeral_seg = reinterpret_cast(&gc_heap::saved_sweep_ephemeral_seg);
gcDacVars->saved_sweep_ephemeral_start = &gc_heap::saved_sweep_ephemeral_start;
#endif //USE_REGIONS
- gcDacVars->background_saved_lowest_address = &gc_heap::background_saved_lowest_address;
- gcDacVars->background_saved_highest_address = &gc_heap::background_saved_highest_address;
+#else //BACKGROUND_GC
+ gcDacVars->mark_array = 0;
+ gcDacVars->background_saved_lowest_address = 0;
+ gcDacVars->background_saved_highest_address = 0;
+ gcDacVars->next_sweep_obj = 0;
+ gcDacVars->saved_sweep_ephemeral_seg = 0;
+ gcDacVars->saved_sweep_ephemeral_start = 0;
+#endif //BACKGROUND_GC
gcDacVars->alloc_allocated = &gc_heap::alloc_allocated;
- gcDacVars->next_sweep_obj = &gc_heap::next_sweep_obj;
gcDacVars->oom_info = &gc_heap::oom_info;
gcDacVars->finalize_queue = reinterpret_cast(&gc_heap::finalize_queue);
gcDacVars->generation_table = reinterpret_cast(&gc_heap::generation_table);
diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h
index 1fd5f0421daa8..051dd99301490 100644
--- a/src/coreclr/gc/gcpriv.h
+++ b/src/coreclr/gc/gcpriv.h
@@ -85,8 +85,10 @@ inline void FATAL_GC_ERROR()
#define FEATURE_PREMORTEM_FINALIZATION
#define GC_HISTORY
+#define BACKGROUND_GC //concurrent background GC (requires WRITE_WATCH)
+
// We need the lower 3 bits in the MT to do our bookkeeping so doubly linked free list is only for 64-bit
-#ifdef HOST_64BIT
+#if defined(BACKGROUND_GC) && defined(HOST_64BIT)
#define DOUBLY_LINKED_FL
#endif //HOST_64BIT
@@ -99,8 +101,6 @@ inline void FATAL_GC_ERROR()
#define initial_internal_roots (1024*16)
#endif // HEAP_ANALYZE
-#define BACKGROUND_GC //concurrent background GC (requires WRITE_WATCH)
-
#ifdef SERVER_GC
#define MH_SC_MARK //scalable marking
//#define SNOOP_STATS //diagnostic
@@ -2038,11 +2038,11 @@ class gc_heap
#endif //!USE_REGIONS
PER_HEAP_ISOLATED
void distribute_free_regions();
+#ifdef BACKGROUND_GC
PER_HEAP_ISOLATED
void reset_write_watch_for_gc_heap(void* base_address, size_t region_size);
PER_HEAP_ISOLATED
void get_write_watch_for_gc_heap(bool reset, void *base_address, size_t region_size, void** dirty_pages, uintptr_t* dirty_page_count_ref, bool is_runtime_suspended);
-
PER_HEAP
void switch_one_quantum();
PER_HEAP
@@ -2051,6 +2051,7 @@ class gc_heap
void switch_on_reset (BOOL concurrent_p, size_t* current_total_reset_size, size_t last_reset_size);
PER_HEAP
void reset_write_watch (BOOL concurrent_p);
+#endif //BACKGROUND_GC
PER_HEAP
void adjust_ephemeral_limits();
PER_HEAP
@@ -5918,14 +5919,7 @@ inline gc_oh_num heap_segment_oh (heap_segment * inst)
}
}
-#ifdef BACKGROUND_GC
#ifdef USE_REGIONS
-inline
-bool heap_segment_overflow_p (heap_segment* inst)
-{
- return ((inst->flags & heap_segment_flags_overflow) != 0);
-}
-
inline
region_free_list*& heap_segment_containing_free_list (heap_segment* inst)
{
@@ -5939,6 +5933,15 @@ PTR_heap_segment& heap_segment_prev_free_region (heap_segment* inst)
}
#endif //USE_REGIONS
+#ifdef BACKGROUND_GC
+#ifdef USE_REGIONS
+inline
+bool heap_segment_overflow_p (heap_segment* inst)
+{
+ return ((inst->flags & heap_segment_flags_overflow) != 0);
+}
+#endif //USE_REGIONS
+
inline
BOOL heap_segment_decommitted_p (heap_segment * inst)
{
diff --git a/src/coreclr/inc/clr_std/vector b/src/coreclr/inc/clr_std/vector
index 0bed04182a4ee..c10ecf6ba5a92 100644
--- a/src/coreclr/inc/clr_std/vector
+++ b/src/coreclr/inc/clr_std/vector
@@ -373,6 +373,11 @@ namespace std
m_size -= elements;
return iterator(m_pelements + (position - begin()));
}
+
+ T* data()
+ {
+ return m_pelements;
+ }
const T* data() const
{
diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h
index 58cb0aa7f9ca8..f9d4b5abf3b8b 100644
--- a/src/coreclr/inc/corhdr.h
+++ b/src/coreclr/inc/corhdr.h
@@ -227,7 +227,7 @@ typedef struct IMAGE_COR20_HEADER
};
// This is the blob of managed resources. Fetched using code:AssemblyNative.GetResource and
- // code:PEFile.GetResource and accessible from managed code from
+ // code:PEAssembly.GetResource and accessible from managed code from
// System.Assembly.GetManifestResourceStream. The meta data has a table that maps names to offsets into
// this blob, so logically the blob is a set of resources.
IMAGE_DATA_DIRECTORY Resources;
diff --git a/src/coreclr/inc/daccess.h b/src/coreclr/inc/daccess.h
index 82009b77890e2..b769fcec22b4b 100644
--- a/src/coreclr/inc/daccess.h
+++ b/src/coreclr/inc/daccess.h
@@ -769,7 +769,7 @@ HRESULT DacReplacePatchesInHostMemory(MemoryRange range, PVOID pBuffer);
#ifdef __cplusplus
}
class ReflectionModule;
-interface IMDInternalImport* DacGetMDImport(const class PEFile* peFile,
+interface IMDInternalImport* DacGetMDImport(const class PEAssembly* pPEAssembly,
bool throwEx);
interface IMDInternalImport* DacGetMDImport(const ReflectionModule* reflectionModule,
bool throwEx);
diff --git a/src/coreclr/inc/dacprivate.h b/src/coreclr/inc/dacprivate.h
index 99419667a9635..45a4eda3cc140 100644
--- a/src/coreclr/inc/dacprivate.h
+++ b/src/coreclr/inc/dacprivate.h
@@ -230,8 +230,8 @@ struct MSLAYOUT DacpThreadLocalModuleData
struct MSLAYOUT DacpModuleData
{
CLRDATA_ADDRESS Address = 0;
- CLRDATA_ADDRESS File = 0; // A PEFile addr
- CLRDATA_ADDRESS ilBase = 0;
+ CLRDATA_ADDRESS PEAssembly = 0; // A PEAssembly addr
+ CLRDATA_ADDRESS ilBase = 0;
CLRDATA_ADDRESS metadataStart = 0;
ULONG64 metadataSize = 0;
CLRDATA_ADDRESS Assembly = 0; // Assembly pointer
@@ -981,7 +981,7 @@ struct MSLAYOUT DacpGetModuleData
BOOL IsDynamic = FALSE;
BOOL IsInMemory = FALSE;
BOOL IsFileLayout = FALSE;
- CLRDATA_ADDRESS PEFile = 0;
+ CLRDATA_ADDRESS PEAssembly = 0;
CLRDATA_ADDRESS LoadedPEAddress = 0;
ULONG64 LoadedPESize = 0;
CLRDATA_ADDRESS InMemoryPdbAddress = 0;
diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h
index 4ea50d9fe4f44..4f8baccd5cd68 100644
--- a/src/coreclr/inc/vptr_list.h
+++ b/src/coreclr/inc/vptr_list.h
@@ -39,7 +39,6 @@ VPTR_CLASS(DelegateInvokeStubManager)
VPTR_CLASS(TailCallStubManager)
#endif
VPTR_CLASS(CallCountingStubManager)
-VPTR_CLASS(PEFile)
VPTR_CLASS(PEAssembly)
VPTR_CLASS(PEImageLayout)
VPTR_CLASS(RawImageLayout)
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index d0395283eb384..ef779db9fcf56 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -118,6 +118,59 @@ bool IntegralRange::Contains(int64_t value) const
}
}
+//------------------------------------------------------------------------
+// ForNode: Compute the integral range for a node.
+//
+// Arguments:
+// node - the node, of an integral type, in question
+// compiler - the Compiler, used to retrieve additional info
+//
+// Return Value:
+// The integral range this node produces.
+//
+/* static */ IntegralRange IntegralRange::ForNode(GenTree* node, Compiler* compiler)
+{
+ assert(varTypeIsIntegral(node));
+
+ var_types rangeType = node->TypeGet();
+
+ switch (node->OperGet())
+ {
+ case GT_EQ:
+ case GT_NE:
+ case GT_LT:
+ case GT_LE:
+ case GT_GE:
+ case GT_GT:
+ return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
+
+ case GT_ARR_LENGTH:
+ return {SymbolicIntegerValue::Zero, SymbolicIntegerValue::IntMax};
+
+ case GT_CALL:
+ if (node->AsCall()->NormalizesSmallTypesOnReturn())
+ {
+ rangeType = static_cast(node->AsCall()->gtReturnType);
+ }
+ break;
+
+ case GT_LCL_VAR:
+ if (compiler->lvaGetDesc(node->AsLclVar())->lvNormalizeOnStore())
+ {
+ rangeType = compiler->lvaGetDesc(node->AsLclVar())->TypeGet();
+ }
+ break;
+
+ case GT_CAST:
+ return ForCastOutput(node->AsCast());
+
+ default:
+ break;
+ }
+
+ return ForType(rangeType);
+}
+
//------------------------------------------------------------------------
// ForCastInput: Get the non-overflowing input range for a cast.
//
@@ -214,7 +267,14 @@ bool IntegralRange::Contains(int64_t value) const
// CAST_OVF(long <- ulong) - [0..LONG_MAX]
// CAST_OVF(long <- long) - [LONG_MIN..LONG_MAX]
case TYP_LONG:
- lowerBound = fromUnsigned ? SymbolicIntegerValue::Zero : LowerBoundForType(fromType);
+ if (fromUnsigned && (fromType == TYP_LONG))
+ {
+ lowerBound = SymbolicIntegerValue::Zero;
+ }
+ else
+ {
+ lowerBound = LowerBoundForType(fromType);
+ }
upperBound = UpperBoundForType(fromType);
break;
@@ -1545,12 +1605,17 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
}
// Try and see if we can make a subrange assertion.
- if (((assertionKind == OAK_SUBRANGE) || (assertionKind == OAK_EQUAL)))
+ if (((assertionKind == OAK_SUBRANGE) || (assertionKind == OAK_EQUAL)) && varTypeIsIntegral(op2))
{
- if (optTryExtractSubrangeAssertion(op2, &assertion.op2.u2))
+ IntegralRange nodeRange = IntegralRange::ForNode(op2, this);
+ IntegralRange typeRange = IntegralRange::ForType(genActualType(op2));
+ assert(typeRange.Contains(nodeRange));
+
+ if (!typeRange.Equals(nodeRange))
{
assertion.op2.kind = O2K_SUBRANGE;
assertion.assertionKind = OAK_SUBRANGE;
+ assertion.op2.u2 = nodeRange;
}
}
}
@@ -1689,73 +1754,6 @@ AssertionIndex Compiler::optFinalizeCreatingAssertion(AssertionDsc* assertion)
return optAddAssertion(assertion);
}
-//------------------------------------------------------------------------
-// optTryExtractSubrangeAssertion: Extract the bounds of the value a tree produces.
-//
-// Generates [0..1] ranges for relops, [T_MIN..T_MAX] for small-typed indirections
-// and casts to small types. Generates various ranges for casts to and from "large"
-// types - see "IntegralRange::ForCastOutput".
-//
-// Arguments:
-// source - tree producing the value
-// pRange - [out] parameter for the range
-//
-// Return Value:
-// "true" if the "source" computes a value that could be used for a subrange
-// assertion, i. e. narrower than the range of the node's type.
-//
-// Notes:
-// The "pRange" parameter is only written to if the function returns "true".
-//
-bool Compiler::optTryExtractSubrangeAssertion(GenTree* source, IntegralRange* pRange)
-{
- var_types sourceType = TYP_UNDEF;
-
- switch (source->OperGet())
- {
- case GT_EQ:
- case GT_NE:
- case GT_LT:
- case GT_LE:
- case GT_GT:
- case GT_GE:
- *pRange = {SymbolicIntegerValue::Zero, SymbolicIntegerValue::One};
- return true;
-
- case GT_CLS_VAR:
- case GT_LCL_FLD:
- case GT_IND:
- sourceType = source->TypeGet();
- break;
-
- case GT_CAST:
- if (varTypeIsIntegral(source))
- {
- IntegralRange castRange = IntegralRange::ForCastOutput(source->AsCast());
- IntegralRange nodeRange = IntegralRange::ForType(source->TypeGet());
- assert(nodeRange.Contains(castRange));
-
- if (!castRange.Equals(nodeRange))
- {
- *pRange = castRange;
- return true;
- }
- }
- return false;
-
- default:
- return false;
- }
-
- if (varTypeIsSmall(sourceType))
- {
- *pRange = IntegralRange::ForType(sourceType);
- return true;
- }
-
- return false;
-}
-
/*****************************************************************************
*
* If tree is a constant node holding an integral value, retrieve the value in
@@ -5412,7 +5410,14 @@ GenTree* Compiler::optExtractSideEffListFromConst(GenTree* tree)
{
// Do a sanity check to ensure persistent side effects aren't discarded and
// tell gtExtractSideEffList to ignore the root of the tree.
- assert(!gtNodeHasSideEffects(tree, GTF_PERSISTENT_SIDE_EFFECTS));
+ // We are relying here on an invariant that VN will only fold non-throwing expressions.
+ const bool ignoreExceptions = true;
+ const bool ignoreCctors = false;
+ // We have to check "AsCall()->HasSideEffects()" here separately because "gtNodeHasSideEffects"
+ // also checks for side effects that arguments introduce (incosistently so, it otherwise only
+ // checks for the side effects the node itself has). TODO-Cleanup: change it to not do that?
+ assert(!gtNodeHasSideEffects(tree, GTF_PERSISTENT_SIDE_EFFECTS) ||
+ (tree->IsCall() && !tree->AsCall()->HasSideEffects(this, ignoreExceptions, ignoreCctors)));
// Exception side effects may be ignored because the root is known to be a constant
// (e.g. VN may evaluate a DIV/MOD node to a constant and the node may still
@@ -5612,6 +5617,13 @@ Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, Sta
}
break;
+ case GT_CALL:
+ if (!tree->AsCall()->IsPure(this))
+ {
+ return WALK_CONTINUE;
+ }
+ break;
+
default:
// Unknown node, continue to walk.
return WALK_CONTINUE;
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h
index 7fb88ab2b5806..59894b1b46056 100644
--- a/src/coreclr/jit/codegen.h
+++ b/src/coreclr/jit/codegen.h
@@ -1145,10 +1145,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genConsumeHWIntrinsicOperands(GenTreeHWIntrinsic* tree);
#endif // FEATURE_HW_INTRINSICS
void genEmitGSCookieCheck(bool pushReg);
- void genSetRegToIcon(regNumber reg,
- ssize_t val,
- var_types type = TYP_INT,
- insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void genCodeForShift(GenTree* tree);
#if defined(TARGET_X86) || defined(TARGET_ARM)
@@ -1259,6 +1255,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
instruction genGetInsForOper(genTreeOps oper, var_types type);
bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
GenTree* getCallTarget(const GenTreeCall* call, CORINFO_METHOD_HANDLE* methHnd);
+ regNumber getCallIndirectionCellReg(const GenTreeCall* call);
void genCall(GenTreeCall* call);
void genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackArgBytes));
void genJmpMethod(GenTree* jmp);
diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp
index 0ae592f0bdbc2..861eac8963611 100644
--- a/src/coreclr/jit/codegenarm.cpp
+++ b/src/coreclr/jit/codegenarm.cpp
@@ -236,15 +236,20 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
GenTreeIntConCommon* con = tree->AsIntConCommon();
ssize_t cnsVal = con->IconValue();
- if (con->ImmedValNeedsReloc(compiler))
+ emitAttr attr = emitActualTypeSize(targetType);
+
+ if (con->IsIconHandle())
{
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
- regSet.verifyRegUsed(targetReg);
+ attr = EA_SET_FLG(attr, EA_CNS_RELOC_FLG);
}
- else
+
+ if (targetType == TYP_BYREF)
{
- genSetRegToIcon(targetReg, cnsVal, targetType);
+ attr = EA_SET_FLG(attr, EA_BYREF_FLG);
}
+
+ instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal);
+ regSet.verifyRegUsed(targetReg);
}
break;
@@ -259,7 +264,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
regNumber tmpReg = tree->GetSingleTempReg();
float f = forceCastToFloat(constValue);
- genSetRegToIcon(tmpReg, *((int*)(&f)));
+ instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg, *((int*)(&f)));
GetEmitter()->emitIns_Mov(INS_vmov_i2f, EA_4BYTE, targetReg, tmpReg, /* canSkip */ false);
}
else
@@ -272,8 +277,8 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
regNumber tmpReg1 = tree->ExtractTempReg();
regNumber tmpReg2 = tree->GetSingleTempReg();
- genSetRegToIcon(tmpReg1, cv[0]);
- genSetRegToIcon(tmpReg2, cv[1]);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg1, cv[0]);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg2, cv[1]);
GetEmitter()->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, tmpReg1, tmpReg2);
}
@@ -460,7 +465,7 @@ void CodeGen::genLclHeap(GenTree* tree)
}
// regCnt will be the total number of bytes to locAlloc
- genSetRegToIcon(regCnt, amount, TYP_INT);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, regCnt, amount);
}
else
{
@@ -1883,4 +1888,36 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
#endif // USING_SCOPE_INFO
}
+//-----------------------------------------------------------------------------------
+// instGen_MemoryBarrier: Emit a MemoryBarrier instruction
+//
+// Arguments:
+// barrierKind - kind of barrier to emit (ignored on arm32)
+//
+// Notes:
+// All MemoryBarriers instructions can be removed by DOTNET_JitNoMemoryBarriers=1
+// barrierKind argument is ignored on arm32 and a full memory barrier is emitted
+//
+void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
+{
+#ifdef DEBUG
+ if (JitConfig.JitNoMemoryBarriers() == 1)
+ {
+ return;
+ }
+#endif // DEBUG
+
+ // Avoid emitting redundant memory barriers on arm32 if they belong to the same IG
+ // and there were no memory accesses in-between them
+ if ((GetEmitter()->emitLastMemBarrier != nullptr) && compiler->opts.OptimizationEnabled())
+ {
+ assert(GetEmitter()->emitLastMemBarrier->idSmallCns() == INS_BARRIER_SY);
+ }
+ else
+ {
+ // ARM has only full barriers, so all barriers need to be emitted as full.
+ GetEmitter()->emitIns_I(INS_dmb, EA_4BYTE, INS_BARRIER_SY);
+ }
+}
+
#endif // TARGET_ARM
diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp
index 0d4d9e9da2c20..c23a705096caf 100644
--- a/src/coreclr/jit/codegenarm64.cpp
+++ b/src/coreclr/jit/codegenarm64.cpp
@@ -1697,17 +1697,21 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
GenTreeIntConCommon* con = tree->AsIntConCommon();
ssize_t cnsVal = con->IconValue();
- if (con->ImmedValNeedsReloc(compiler))
+ emitAttr attr = emitActualTypeSize(targetType);
+ if (con->IsIconHandle())
{
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal,
- INS_FLAGS_DONT_CARE DEBUGARG(tree->AsIntCon()->gtTargetHandle)
- DEBUGARG(tree->AsIntCon()->gtFlags));
- regSet.verifyRegUsed(targetReg);
+ attr = EA_SET_FLG(attr, EA_CNS_RELOC_FLG);
}
- else
+
+ if (targetType == TYP_BYREF)
{
- genSetRegToIcon(targetReg, cnsVal, targetType);
+ attr = EA_SET_FLG(attr, EA_BYREF_FLG);
}
+
+ instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal,
+ INS_FLAGS_DONT_CARE DEBUGARG(tree->AsIntCon()->gtTargetHandle)
+ DEBUGARG(tree->AsIntCon()->gtFlags));
+ regSet.verifyRegUsed(targetReg);
}
break;
@@ -2279,7 +2283,7 @@ void CodeGen::genLclHeap(GenTree* tree)
{
regCnt = tree->ExtractTempReg();
}
- genSetRegToIcon(regCnt, amount, ((unsigned int)amount == amount) ? TYP_INT : TYP_LONG);
+ instGen_Set_Reg_To_Imm(((unsigned int)amount == amount) ? EA_4BYTE : EA_8BYTE, regCnt, amount);
}
if (compiler->info.compInitMem)
@@ -4623,7 +4627,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
}
else
{
- genSetRegToIcon(REG_PROFILER_ENTER_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_PROFILER_ENTER_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd);
}
int callerSPOffset = compiler->lvaToCallerSPRelativeOffset(0, isFramePointerUsed());
@@ -4667,7 +4671,7 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper)
}
else
{
- genSetRegToIcon(REG_PROFILER_LEAVE_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd);
}
gcInfo.gcMarkRegSetNpt(RBM_PROFILER_LEAVE_ARG_FUNC_ID);
@@ -9510,4 +9514,54 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
}
}
+//-----------------------------------------------------------------------------------
+// instGen_MemoryBarrier: Emit a MemoryBarrier instruction
+//
+// Arguments:
+// barrierKind - kind of barrier to emit (Full or Load-Only).
+//
+// Notes:
+// All MemoryBarriers instructions can be removed by DOTNET_JitNoMemoryBarriers=1
+//
+void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
+{
+#ifdef DEBUG
+ if (JitConfig.JitNoMemoryBarriers() == 1)
+ {
+ return;
+ }
+#endif // DEBUG
+
+ // Avoid emitting redundant memory barriers on arm64 if they belong to the same IG
+ // and there were no memory accesses in-between them
+ emitter::instrDesc* lastMemBarrier = GetEmitter()->emitLastMemBarrier;
+ if ((lastMemBarrier != nullptr) && compiler->opts.OptimizationEnabled())
+ {
+ BarrierKind prevBarrierKind = BARRIER_FULL;
+ if (lastMemBarrier->idSmallCns() == INS_BARRIER_ISHLD)
+ {
+ prevBarrierKind = BARRIER_LOAD_ONLY;
+ }
+ else
+ {
+ // Currently we only emit two kinds of barriers on arm64:
+ // ISH - Full (inner shareable domain)
+ // ISHLD - LoadOnly (inner shareable domain)
+ assert(lastMemBarrier->idSmallCns() == INS_BARRIER_ISH);
+ }
+
+ if ((prevBarrierKind == BARRIER_LOAD_ONLY) && (barrierKind == BARRIER_FULL))
+ {
+ // Previous memory barrier: load-only, current: full
+ // Upgrade the previous one to full
+ assert((prevBarrierKind == BARRIER_LOAD_ONLY) && (barrierKind == BARRIER_FULL));
+ lastMemBarrier->idSmallCns(INS_BARRIER_ISH);
+ }
+ }
+ else
+ {
+ GetEmitter()->emitIns_BARR(INS_dmb, barrierKind == BARRIER_LOAD_ONLY ? INS_BARRIER_ISHLD : INS_BARRIER_ISH);
+ }
+}
+
#endif // TARGET_ARM64
diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp
index 68453abaaf7cd..31d7ef94e3afd 100644
--- a/src/coreclr/jit/codegenarmarch.cpp
+++ b/src/coreclr/jit/codegenarmarch.cpp
@@ -553,22 +553,6 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
}
}
-//------------------------------------------------------------------------
-// genSetRegToIcon: Generate code that will set the given register to the integer constant.
-//
-void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags DEBUGARG(GenTreeFlags gtFlags))
-{
- // Reg cannot be a FP reg
- assert(!genIsValidFloatReg(reg));
-
- // The only TYP_REF constant that can come this path is a managed 'null' since it is not
- // relocatable. Other ref type constants (e.g. string objects) go through a different
- // code path.
- noway_assert(type != TYP_REF || val == 0);
-
- instGen_Set_Reg_To_Imm(emitActualTypeSize(type), reg, val, flags);
-}
-
//---------------------------------------------------------------------
// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog.
//
@@ -593,7 +577,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
{
noway_assert(compiler->gsGlobalSecurityCookieVal != 0);
// initReg = #GlobalSecurityCookieVal; [frame.GSSecurityCookie] = initReg
- genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, initReg, compiler->gsGlobalSecurityCookieVal);
GetEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
}
else
@@ -1817,7 +1801,7 @@ void CodeGen::genCodeForIndexAddr(GenTreeIndexAddr* node)
else // we have to load the element size and use a MADD (multiply-add) instruction
{
// tmpReg = element size
- CodeGen::genSetRegToIcon(tmpReg, (ssize_t)node->gtElemSize, TYP_INT);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, tmpReg, (ssize_t)node->gtElemSize);
// dest = index * tmpReg + base
GetEmitter()->emitIns_R_R_R_R(INS_MULADD, emitActualTypeSize(node), node->GetRegNum(), index->GetRegNum(),
@@ -2565,109 +2549,109 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
call->IsFastTailCall());
// clang-format on
}
- else if (call->IsR2ROrVirtualStubRelativeIndir())
- {
- // Generate a indirect call to a virtual user defined function or helper method
- assert(call->gtCallType == CT_HELPER || call->gtCallType == CT_USER_FUNC);
-#ifdef FEATURE_READYTORUN
- assert(((call->IsR2RRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_PVALUE)) ||
- ((call->IsVirtualStubRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_VALUE)));
-#endif // FEATURE_READYTORUN
- assert(call->gtControlExpr == nullptr);
-
- regNumber tmpReg = call->GetSingleTempReg();
- // For fast tailcalls we have already loaded the call target when processing the call node.
- if (!call->IsFastTailCall())
- {
- regNumber callAddrReg =
- call->IsVirtualStubRelativeIndir() ? compiler->virtualStubParamInfo->GetReg() : REG_R2R_INDIRECT_PARAM;
- GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, callAddrReg);
- }
- else
- {
- // Register where we save call address in should not be overridden by epilog.
- assert((tmpReg & (RBM_INT_CALLEE_TRASH & ~RBM_LR)) == tmpReg);
- }
-
- // We have now generated code for gtControlExpr evaluating it into `tmpReg`.
- // We just need to emit "call tmpReg" in this case.
- //
- assert(genIsValidIntReg(tmpReg));
-
- // clang-format off
- genEmitCall(emitter::EC_INDIR_R,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- nullptr, // addr
- retSize
- MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
- ilOffset,
- tmpReg,
- call->IsFastTailCall());
- // clang-format on
- }
else
{
- // Generate a direct call to a non-virtual user defined or helper method
- assert(call->gtCallType == CT_HELPER || call->gtCallType == CT_USER_FUNC);
-
- void* addr = nullptr;
-#ifdef FEATURE_READYTORUN
- if (call->gtEntryPoint.addr != NULL)
- {
- assert(call->gtEntryPoint.accessType == IAT_VALUE);
- addr = call->gtEntryPoint.addr;
- }
- else
-#endif // FEATURE_READYTORUN
- if (call->gtCallType == CT_HELPER)
- {
- CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
- noway_assert(helperNum != CORINFO_HELP_UNDEF);
-
- void* pAddr = nullptr;
- addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
- assert(pAddr == nullptr);
- }
- else
+ // If we have no target and this is a call with indirection cell
+ // then we do an optimization where we load the call address directly
+ // from the indirection cell instead of duplicating the tree.
+ // In BuildCall we ensure that get an extra register for the purpose.
+ regNumber indirCellReg = getCallIndirectionCellReg(call);
+ if (indirCellReg != REG_NA)
{
- // Direct call to a non-virtual user function.
- addr = call->gtDirectCallAddress;
- }
+ assert(call->IsR2ROrVirtualStubRelativeIndir());
+ regNumber targetAddrReg = call->GetSingleTempReg();
+ // For fast tailcalls we have already loaded the call target when processing the call node.
+ if (!call->IsFastTailCall())
+ {
+ GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), targetAddrReg,
+ indirCellReg);
+ }
+ else
+ {
+ // Register where we save call address in should not be overridden by epilog.
+ assert((targetAddrReg & (RBM_INT_CALLEE_TRASH & ~RBM_LR)) == targetAddrReg);
+ }
- assert(addr != nullptr);
+ // We have now generated code loading the target address from the indirection cell into `targetAddrReg`.
+ // We just need to emit "bl targetAddrReg" in this case.
+ //
+ assert(genIsValidIntReg(targetAddrReg));
-// Non-virtual direct call to known addresses
-#ifdef TARGET_ARM
- if (!arm_Valid_Imm_For_BL((ssize_t)addr))
- {
- regNumber tmpReg = call->GetSingleTempReg();
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr);
// clang-format off
genEmitCall(emitter::EC_INDIR_R,
methHnd,
INDEBUG_LDISASM_COMMA(sigInfo)
- NULL,
- retSize,
+ nullptr, // addr
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
ilOffset,
- tmpReg,
+ targetAddrReg,
call->IsFastTailCall());
// clang-format on
}
else
-#endif // TARGET_ARM
{
- // clang-format off
- genEmitCall(emitter::EC_FUNC_TOKEN,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr,
- retSize
- MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
- ilOffset,
- REG_NA,
- call->IsFastTailCall());
- // clang-format on
+ // Generate a direct call to a non-virtual user defined or helper method
+ assert(call->gtCallType == CT_HELPER || call->gtCallType == CT_USER_FUNC);
+
+ void* addr = nullptr;
+#ifdef FEATURE_READYTORUN
+ if (call->gtEntryPoint.addr != NULL)
+ {
+ assert(call->gtEntryPoint.accessType == IAT_VALUE);
+ addr = call->gtEntryPoint.addr;
+ }
+ else
+#endif // FEATURE_READYTORUN
+ if (call->gtCallType == CT_HELPER)
+ {
+ CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
+ noway_assert(helperNum != CORINFO_HELP_UNDEF);
+
+ void* pAddr = nullptr;
+ addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
+ assert(pAddr == nullptr);
+ }
+ else
+ {
+ // Direct call to a non-virtual user function.
+ addr = call->gtDirectCallAddress;
+ }
+
+ assert(addr != nullptr);
+
+// Non-virtual direct call to known addresses
+#ifdef TARGET_ARM
+ if (!arm_Valid_Imm_For_BL((ssize_t)addr))
+ {
+ regNumber tmpReg = call->GetSingleTempReg();
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, tmpReg, (ssize_t)addr);
+ // clang-format off
+ genEmitCall(emitter::EC_INDIR_R,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ NULL,
+ retSize,
+ ilOffset,
+ tmpReg,
+ call->IsFastTailCall());
+ // clang-format on
+ }
+ else
+#endif // TARGET_ARM
+ {
+ // clang-format off
+ genEmitCall(emitter::EC_FUNC_TOKEN,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ addr,
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset,
+ REG_NA,
+ call->IsFastTailCall());
+ // clang-format on
+ }
}
}
}
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index 15fac8b26ae0f..38a134cbe67a4 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1794,7 +1794,7 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
{
// load the GS cookie constant into a reg
//
- genSetRegToIcon(regGSConst, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, regGSConst, compiler->gsGlobalSecurityCookieVal);
}
else
{
@@ -7802,6 +7802,55 @@ GenTree* CodeGen::getCallTarget(const GenTreeCall* call, CORINFO_METHOD_HANDLE*
return call->gtControlExpr;
}
+//------------------------------------------------------------------------
+// getCallIndirectionCellReg - Get the register containing the indirection cell for a call
+//
+// Arguments:
+// call - the node
+//
+// Returns:
+// The register containing the indirection cell, or REG_NA if this call does not use an indirection cell argument.
+//
+// Notes:
+// We currently use indirection cells for VSD on all platforms and for R2R calls on ARM architectures.
+//
+regNumber CodeGen::getCallIndirectionCellReg(const GenTreeCall* call)
+{
+ regNumber result = REG_NA;
+ switch (call->GetIndirectionCellArgKind())
+ {
+ case NonStandardArgKind::None:
+ break;
+ case NonStandardArgKind::R2RIndirectionCell:
+ result = REG_R2R_INDIRECT_PARAM;
+ break;
+ case NonStandardArgKind::VirtualStubCell:
+ result = compiler->virtualStubParamInfo->GetReg();
+ break;
+ default:
+ unreached();
+ }
+
+#ifdef DEBUG
+ regNumber foundReg = REG_NA;
+ unsigned argCount = call->fgArgInfo->ArgCount();
+ fgArgTabEntry** argTable = call->fgArgInfo->ArgTable();
+ for (unsigned i = 0; i < argCount; i++)
+ {
+ NonStandardArgKind kind = argTable[i]->nonStandardArgKind;
+ if ((kind == NonStandardArgKind::R2RIndirectionCell) || (kind == NonStandardArgKind::VirtualStubCell))
+ {
+ foundReg = argTable[i]->GetRegNum();
+ break;
+ }
+ }
+
+ assert(foundReg == result);
+#endif
+
+ return result;
+}
+
/*****************************************************************************
*
* Generates code for a function epilog.
@@ -12565,9 +12614,9 @@ void CodeGen::genPoisonFrame(regMaskTP regLiveIn)
if (!hasPoisonImm)
{
#ifdef TARGET_64BIT
- genSetRegToIcon(REG_SCRATCH, (ssize_t)0xcdcdcdcdcdcdcdcd, TYP_LONG);
+ instGen_Set_Reg_To_Imm(EA_8BYTE, REG_SCRATCH, (ssize_t)0xcdcdcdcdcdcdcdcd);
#else
- genSetRegToIcon(REG_SCRATCH, (ssize_t)0xcdcdcdcd, TYP_INT);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, REG_SCRATCH, (ssize_t)0xcdcdcdcd);
#endif
hasPoisonImm = true;
}
diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp
index 7b9be941ab4e8..c9251065ce5b9 100644
--- a/src/coreclr/jit/codegenlinear.cpp
+++ b/src/coreclr/jit/codegenlinear.cpp
@@ -1898,7 +1898,7 @@ void CodeGen::genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg)
if (!blkNode->OperIs(GT_STORE_DYN_BLK))
{
assert((blkNode->gtRsvdRegs & genRegMask(sizeReg)) != 0);
- genSetRegToIcon(sizeReg, blockSize);
+ instGen_Set_Reg_To_Imm(EA_4BYTE, sizeReg, blockSize);
}
else
{
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 9c280d6e63977..df37565b4242a 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -23,32 +23,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "gcinfoencoder.h"
#include "patchpointinfo.h"
-/*****************************************************************************
- *
- * Generate code that will set the given register to the integer constant.
- */
-
-void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags DEBUGARG(GenTreeFlags gtFlags))
-{
- // Reg cannot be a FP reg
- assert(!genIsValidFloatReg(reg));
-
- // The only TYP_REF constant that can come this path is a managed 'null' since it is not
- // relocatable. Other ref type constants (e.g. string objects) go through a different
- // code path.
- noway_assert(type != TYP_REF || val == 0);
-
- if (val == 0)
- {
- instGen_Set_Reg_To_Zero(emitActualTypeSize(type), reg, flags);
- }
- else
- {
- // TODO-XArch-CQ: needs all the optimized cases
- GetEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(type), reg, val DEBUGARG(gtFlags));
- }
-}
-
//---------------------------------------------------------------------
// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog.
//
@@ -82,7 +56,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
if ((size_t)(int)compiler->gsGlobalSecurityCookieVal != compiler->gsGlobalSecurityCookieVal)
{
// initReg = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = initReg
- genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, initReg, compiler->gsGlobalSecurityCookieVal);
GetEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
*pInitRegZeroed = false;
}
@@ -230,7 +204,7 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
// Otherwise, load the value into a reg and use 'cmp mem64, reg64'.
if ((int)compiler->gsGlobalSecurityCookieVal != (ssize_t)compiler->gsGlobalSecurityCookieVal)
{
- genSetRegToIcon(regGSCheck, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, regGSCheck, compiler->gsGlobalSecurityCookieVal);
GetEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, regGSCheck, compiler->lvaGSSecurityCookie, 0);
}
else
@@ -445,9 +419,11 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
// reg cannot be a FP register
assert(!genIsValidFloatReg(reg));
+ emitAttr origAttr = size;
if (!compiler->opts.compReloc)
{
- size = EA_SIZE(size); // Strip any Reloc flags from size if we aren't doing relocs
+ // Strip any reloc flags from size if we aren't doing relocs
+ size = EA_REMOVE_FLG(size, EA_CNS_RELOC_FLG | EA_DSP_RELOC_FLG);
}
if ((imm == 0) && !EA_IS_RELOC(size))
@@ -456,19 +432,17 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
}
else
{
- if (genDataIndirAddrCanBeEncodedAsPCRelOffset(imm))
+ // Only use lea if the original was relocatable. Otherwise we can get spurious
+ // instruction selection due to different memory placement at runtime.
+ if (EA_IS_RELOC(origAttr) && genDataIndirAddrCanBeEncodedAsPCRelOffset(imm))
{
- emitAttr newSize = EA_PTR_DSP_RELOC;
- if (EA_IS_BYREF(size))
- {
- newSize = EA_SET_FLG(newSize, EA_BYREF_FLG);
- }
-
- GetEmitter()->emitIns_R_AI(INS_lea, newSize, reg, imm);
+ // We will use lea so displacement and not immediate will be relocatable
+ size = EA_SET_FLG(EA_REMOVE_FLG(size, EA_CNS_RELOC_FLG), EA_DSP_RELOC_FLG);
+ GetEmitter()->emitIns_R_AI(INS_lea, size, reg, imm);
}
else
{
- GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
+ GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm DEBUGARG(gtFlags));
}
}
regSet.verifyRegUsed(reg);
@@ -491,22 +465,19 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
GenTreeIntConCommon* con = tree->AsIntConCommon();
ssize_t cnsVal = con->IconValue();
- if (con->ImmedValNeedsReloc(compiler))
+ emitAttr attr = emitActualTypeSize(targetType);
+ if (con->IsIconHandle())
{
- emitAttr size = EA_HANDLE_CNS_RELOC;
-
- if (targetType == TYP_BYREF)
- {
- size = EA_SET_FLG(size, EA_BYREF_FLG);
- }
-
- instGen_Set_Reg_To_Imm(size, targetReg, cnsVal);
- regSet.verifyRegUsed(targetReg);
+ attr = EA_SET_FLG(attr, EA_CNS_RELOC_FLG);
}
- else
+
+ if (targetType == TYP_BYREF)
{
- genSetRegToIcon(targetReg, cnsVal, targetType, INS_FLAGS_DONT_CARE DEBUGARG(tree->gtFlags));
+ attr = EA_SET_FLG(attr, EA_BYREF_FLG);
}
+
+ instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal, INS_FLAGS_DONT_CARE DEBUGARG(0) DEBUGARG(tree->gtFlags));
+ regSet.verifyRegUsed(targetReg);
}
break;
@@ -2515,7 +2486,7 @@ void CodeGen::genLclHeap(GenTree* tree)
amount /= STACK_ALIGN;
}
- genSetRegToIcon(regCnt, amount, ((size_t)(int)amount == amount) ? TYP_INT : TYP_LONG);
+ instGen_Set_Reg_To_Imm(((size_t)(int)amount == amount) ? EA_4BYTE : EA_8BYTE, regCnt, amount);
}
if (compiler->info.compInitMem)
@@ -5696,15 +5667,18 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
// clang-format on
}
}
-#ifdef FEATURE_READYTORUN
- else if (call->gtEntryPoint.addr != nullptr)
+ else
{
- emitter::EmitCallType type =
- (call->gtEntryPoint.accessType == IAT_VALUE) ? emitter::EC_FUNC_TOKEN : emitter::EC_FUNC_TOKEN_INDIR;
- if (call->IsFastTailCall() && (type == emitter::EC_FUNC_TOKEN_INDIR))
+ // If we have no target and this is a call with indirection cell
+ // then emit call through that indir cell. This means we generate e.g.
+ // lea r11, [addr of cell]
+ // call [r11]
+ // which is more efficent than
+ // lea r11, [addr of cell]
+ // call [addr of cell]
+ regNumber indirCellReg = getCallIndirectionCellReg(call);
+ if (indirCellReg != REG_NA)
{
- // For fast tailcall with func token indir we already have the indirection cell in REG_R2R_INDIRECT_PARAM,
- // so get it from there.
// clang-format off
GetEmitter()->emitIns_Call(
emitter::EC_INDIR_ARD,
@@ -5717,11 +5691,15 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
gcInfo.gcVarPtrSetCur,
gcInfo.gcRegGCrefSetCur,
gcInfo.gcRegByrefSetCur,
- ilOffset, REG_R2R_INDIRECT_PARAM, REG_NA, 0, 0, true);
+ ilOffset, indirCellReg, REG_NA, 0, 0,
+ call->IsFastTailCall());
// clang-format on
}
- else
+#ifdef FEATURE_READYTORUN
+ else if (call->gtEntryPoint.addr != nullptr)
{
+ emitter::EmitCallType type =
+ (call->gtEntryPoint.accessType == IAT_VALUE) ? emitter::EC_FUNC_TOKEN : emitter::EC_FUNC_TOKEN_INDIR;
// clang-format off
genEmitCall(type,
methHnd,
@@ -5735,46 +5713,46 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
call->IsFastTailCall());
// clang-format on
}
- }
#endif
- else
- {
- // Generate a direct call to a non-virtual user defined or helper method
- assert(call->gtCallType == CT_HELPER || call->gtCallType == CT_USER_FUNC);
-
- void* addr = nullptr;
- if (call->gtCallType == CT_HELPER)
- {
- // Direct call to a helper method.
- CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
- noway_assert(helperNum != CORINFO_HELP_UNDEF);
-
- void* pAddr = nullptr;
- addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
- assert(pAddr == nullptr);
- }
else
{
- // Direct call to a non-virtual user function.
- addr = call->gtDirectCallAddress;
- }
+ // Generate a direct call to a non-virtual user defined or helper method
+ assert(call->gtCallType == CT_HELPER || call->gtCallType == CT_USER_FUNC);
- assert(addr != nullptr);
+ void* addr = nullptr;
+ if (call->gtCallType == CT_HELPER)
+ {
+ // Direct call to a helper method.
+ CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(methHnd);
+ noway_assert(helperNum != CORINFO_HELP_UNDEF);
- // Non-virtual direct calls to known addresses
+ void* pAddr = nullptr;
+ addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
+ assert(pAddr == nullptr);
+ }
+ else
+ {
+ // Direct call to a non-virtual user function.
+ addr = call->gtDirectCallAddress;
+ }
- // clang-format off
- genEmitCall(emitter::EC_FUNC_TOKEN,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr
- X86_ARG(argSizeForEmitter),
- retSize
- MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
- ilOffset,
- REG_NA,
- call->IsFastTailCall());
- // clang-format on
+ assert(addr != nullptr);
+
+ // Non-virtual direct calls to known addresses
+
+ // clang-format off
+ genEmitCall(emitter::EC_FUNC_TOKEN,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ addr
+ X86_ARG(argSizeForEmitter),
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset,
+ REG_NA,
+ call->IsFastTailCall());
+ // clang-format on
+ }
}
}
@@ -8443,7 +8421,7 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
#endif
callTarget = callTargetReg;
- CodeGen::genSetRegToIcon(callTarget, (ssize_t)pAddr, TYP_I_IMPL);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, callTarget, (ssize_t)pAddr);
callType = emitter::EC_INDIR_ARD;
}
}
@@ -8818,16 +8796,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
}
else
{
- // No need to record relocations, if we are generating ELT hooks under the influence
- // of COMPlus_JitELTHookEnabled=1
- if (compiler->opts.compJitELTHookEnabled)
- {
- genSetRegToIcon(REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
- }
- else
- {
- instGen_Set_Reg_To_Imm(EA_8BYTE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
- }
+ instGen_Set_Reg_To_Imm(EA_8BYTE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
}
// RDX = caller's SP
@@ -8902,16 +8871,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
}
else
{
- // No need to record relocations, if we are generating ELT hooks under the influence
- // of COMPlus_JitELTHookEnabled=1
- if (compiler->opts.compJitELTHookEnabled)
- {
- genSetRegToIcon(REG_PROFILER_ENTER_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
- }
- else
- {
- instGen_Set_Reg_To_Imm(EA_8BYTE, REG_PROFILER_ENTER_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
- }
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_PROFILER_ENTER_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
}
// R15 = caller's SP
@@ -8990,16 +8950,7 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper)
}
else
{
- // Don't record relocations, if we are generating ELT hooks under the influence
- // of COMPlus_JitELTHookEnabled=1
- if (compiler->opts.compJitELTHookEnabled)
- {
- genSetRegToIcon(REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
- }
- else
- {
- instGen_Set_Reg_To_Imm(EA_8BYTE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
- }
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
}
// RDX = caller's SP
@@ -9040,14 +8991,7 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper)
}
else
{
- if (compiler->opts.compJitELTHookEnabled)
- {
- genSetRegToIcon(REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
- }
- else
- {
- instGen_Set_Reg_To_Imm(EA_8BYTE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
- }
+ instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd);
}
// RSI = caller's SP
@@ -9135,4 +9079,30 @@ void CodeGen::genPushCalleeSavedRegisters()
}
}
+//-----------------------------------------------------------------------------------
+// instGen_MemoryBarrier: Emit a MemoryBarrier instruction
+//
+// Arguments:
+// barrierKind - kind of barrier to emit (Load-only is no-op on xarch)
+//
+// Notes:
+// All MemoryBarriers instructions can be removed by DOTNET_JitNoMemoryBarriers=1
+//
+void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
+{
+#ifdef DEBUG
+ if (JitConfig.JitNoMemoryBarriers() == 1)
+ {
+ return;
+ }
+#endif // DEBUG
+
+ // only full barrier needs to be emitted on Xarch
+ if (barrierKind == BARRIER_FULL)
+ {
+ instGen(INS_lock);
+ GetEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
+ }
+}
+
#endif // TARGET_XARCH
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 7019714bed642..e2f2eb513cb48 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -1216,6 +1216,11 @@ class IntegralRange
return (m_lowerBound <= other.m_lowerBound) && (other.m_upperBound <= m_upperBound);
}
+ bool IsPositive()
+ {
+ return m_lowerBound >= SymbolicIntegerValue::Zero;
+ }
+
bool Equals(IntegralRange other) const
{
return (m_lowerBound == other.m_lowerBound) && (m_upperBound == other.m_upperBound);
@@ -1230,6 +1235,7 @@ class IntegralRange
return {LowerBoundForType(type), UpperBoundForType(type)};
}
+ static IntegralRange ForNode(GenTree* node, Compiler* compiler);
static IntegralRange ForCastInput(GenTreeCast* cast);
static IntegralRange ForCastOutput(GenTreeCast* cast);
@@ -1633,26 +1639,6 @@ struct FuncInfoDsc
// that isn't shared between the main function body and funclets.
};
-enum class NonStandardArgKind : unsigned
-{
- None,
- PInvokeFrame,
- PInvokeTarget,
- PInvokeCookie,
- WrapperDelegateCell,
- ShiftLow,
- ShiftHigh,
- FixedRetBuffer,
- VirtualStubCell,
- R2RIndirectionCell,
-
- // If changing this enum also change getNonStandardArgKindName and isNonStandardArgAddedLate below
-};
-
-#ifdef DEBUG
-const char* getNonStandardArgKindName(NonStandardArgKind kind);
-#endif
-
struct fgArgTabEntry
{
GenTreeCall::Use* use; // Points to the argument's GenTreeCall::Use in gtCallArgs or gtCallThisArg.
@@ -5498,6 +5484,9 @@ class Compiler
// Does value-numbering for a call. We interpret some helper calls.
void fgValueNumberCall(GenTreeCall* call);
+ // Does value-numbering for a helper representing a cast operation.
+ void fgValueNumberCastHelper(GenTreeCall* call);
+
// Does value-numbering for a helper "call" that has a VN function symbol "vnf".
void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
@@ -6363,7 +6352,7 @@ class Compiler
GenTree* fgMorphCopyBlock(GenTree* tree);
GenTree* fgMorphForRegisterFP(GenTree* tree);
GenTree* fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac = nullptr);
- GenTree* fgOptimizeCast(GenTree* tree);
+ GenTree* fgOptimizeCast(GenTreeCast* cast);
GenTree* fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp);
GenTree* fgOptimizeRelationalComparisonWithConst(GenTreeOp* cmp);
GenTree* fgPropagateCommaThrow(GenTree* parent, GenTreeOp* commaThrow, GenTreeFlags precedingSideEffects);
@@ -6376,6 +6365,7 @@ class Compiler
GenTreeLclVar* fgMorphTryFoldObjAsLclVar(GenTreeObj* obj);
GenTree* fgMorphCommutative(GenTreeOp* tree);
+ GenTree* fgMorphCastedBitwiseOp(GenTreeOp* tree);
public:
GenTree* fgMorphTree(GenTree* tree, MorphAddrContext* mac = nullptr);
diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp
index 8bf8e586f34e1..3708f5123a942 100644
--- a/src/coreclr/jit/emit.cpp
+++ b/src/coreclr/jit/emit.cpp
@@ -703,6 +703,11 @@ insGroup* emitter::emitSavIG(bool emitAdd)
ig = emitCurIG;
assert(ig);
+#ifdef TARGET_ARMARCH
+ // Reset emitLastMemBarrier for new IG
+ emitLastMemBarrier = nullptr;
+#endif
+
// Compute how much code we've generated
sz = emitCurIGfreeNext - emitCurIGfreeBase;
@@ -1140,6 +1145,10 @@ void emitter::emitBegFN(bool hasFramePtr
emitLastIns = nullptr;
+#ifdef TARGET_ARMARCH
+ emitLastMemBarrier = nullptr;
+#endif
+
ig->igNext = nullptr;
#ifdef DEBUG
@@ -1303,6 +1312,17 @@ void emitter::dispIns(instrDesc* id)
void emitter::appendToCurIG(instrDesc* id)
{
+#ifdef TARGET_ARMARCH
+ if (id->idIns() == INS_dmb)
+ {
+ emitLastMemBarrier = id;
+ }
+ else if (emitInsIsLoadOrStore(id->idIns()))
+ {
+ // A memory access - reset saved memory barrier
+ emitLastMemBarrier = nullptr;
+ }
+#endif
emitCurIGsize += id->idCodeSize();
}
diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h
index d84ede9ed63e8..23d5e0327db57 100644
--- a/src/coreclr/jit/emit.h
+++ b/src/coreclr/jit/emit.h
@@ -1884,6 +1884,10 @@ class emitter
instrDesc* emitLastIns;
+#ifdef TARGET_ARMARCH
+ instrDesc* emitLastMemBarrier;
+#endif
+
#ifdef DEBUG
void emitCheckIGoffsets();
#endif
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index dda2f217a7f7b..788034227f3c4 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -8846,7 +8846,12 @@ void emitter::emitDispIns(
}
else
{
- printf("%s", sstr);
+ // GC ref bit is for the return value for calls, do not print it before the address mode
+ if ((ins != INS_call) && (ins != INS_tail_i_jmp))
+ {
+ printf("%s", sstr);
+ }
+
emitDispAddrMode(id, isNew);
emitDispShift(ins);
}
@@ -10292,7 +10297,7 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc)
noway_assert((int)dsp == dsp);
// This requires, specifying a SIB byte after ModRM byte.
- if (EncodedBySSE38orSSE3A(ins))
+ if (EncodedBySSE38orSSE3A(ins) || (ins == INS_crc32))
{
dst += emitOutputByte(dst, code | 0x04);
}
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 800a09399012d..d58f0f202ab0d 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -15908,7 +15908,7 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
{
if (m_compiler->gtNodeHasSideEffects(node, m_flags))
{
- m_sideEffects.Push(node);
+ PushSideEffects(node);
if (node->OperIsBlk() && !node->OperIsStoreBlk())
{
JITDUMP("Replace an unused OBJ/BLK node [%06d] with a NULLCHECK\n", dspTreeID(node));
@@ -15925,7 +15925,7 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
// gtNodeHasSideEffects and make this check unconditionally.
if (node->OperIsAtomicOp())
{
- m_sideEffects.Push(node);
+ PushSideEffects(node);
return Compiler::WALK_SKIP_SUBTREES;
}
@@ -15936,7 +15936,7 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
(node->gtGetOp1()->TypeGet() == TYP_STRUCT))
{
JITDUMP("Keep the GT_ADDR and GT_IND together:\n");
- m_sideEffects.Push(node);
+ PushSideEffects(node);
return Compiler::WALK_SKIP_SUBTREES;
}
}
@@ -15953,7 +15953,7 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
// those need to be extracted as if they're side effects.
if (!UnmarkCSE(node))
{
- m_sideEffects.Push(node);
+ PushSideEffects(node);
return Compiler::WALK_SKIP_SUBTREES;
}
@@ -15989,6 +15989,16 @@ void Compiler::gtExtractSideEffList(GenTree* expr,
return false;
}
}
+
+ void PushSideEffects(GenTree* node)
+ {
+ // The extracted side effect will no longer be an argument, so unmark it.
+ // This is safe to do because the side effects will be visited in pre-order,
+ // aborting as soon as any tree is extracted. Thus if an argument for a call
+ // is being extracted, it is guaranteed that the call itself will not be.
+ node->gtFlags &= ~GTF_LATE_ARG;
+ m_sideEffects.Push(node);
+ }
};
SideEffectExtractor extractor(this, flags);
diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h
index db7c56072130e..1741b2257f3bc 100644
--- a/src/coreclr/jit/gentree.h
+++ b/src/coreclr/jit/gentree.h
@@ -4101,6 +4101,26 @@ class TailCallSiteInfo
class fgArgInfo;
+enum class NonStandardArgKind : unsigned
+{
+ None,
+ PInvokeFrame,
+ PInvokeTarget,
+ PInvokeCookie,
+ WrapperDelegateCell,
+ ShiftLow,
+ ShiftHigh,
+ FixedRetBuffer,
+ VirtualStubCell,
+ R2RIndirectionCell,
+
+ // If changing this enum also change getNonStandardArgKindName and isNonStandardArgAddedLate in fgArgInfo
+};
+
+#ifdef DEBUG
+const char* getNonStandardArgKindName(NonStandardArgKind kind);
+#endif
+
struct GenTreeCall final : public GenTree
{
class Use
@@ -4472,12 +4492,14 @@ struct GenTreeCall final : public GenTree
bool IsR2ROrVirtualStubRelativeIndir()
{
-#if defined(FEATURE_READYTORUN) && defined(TARGET_ARMARCH)
- bool isVirtualStub = (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB;
- return ((IsR2RRelativeIndir()) || (isVirtualStub && (IsVirtualStubRelativeIndir())));
-#else
- return false;
-#endif // FEATURE_READYTORUN && TARGET_ARMARCH
+#if defined(FEATURE_READYTORUN)
+ if (IsR2RRelativeIndir())
+ {
+ return true;
+ }
+#endif
+
+ return IsVirtualStubRelativeIndir();
}
bool HasNonStandardAddedArgs(Compiler* compiler) const;
@@ -4636,6 +4658,11 @@ struct GenTreeCall final : public GenTree
}
#endif // !FEATURE_TAILCALL_OPT
+ bool NormalizesSmallTypesOnReturn()
+ {
+ return GetUnmanagedCallConv() == CorInfoCallConvExtension::Managed;
+ }
+
bool IsSameThis() const
{
return (gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS) != 0;
@@ -4646,7 +4673,7 @@ struct GenTreeCall final : public GenTree
}
bool IsVirtualStubRelativeIndir() const
{
- return (gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0;
+ return IsVirtualStub() && (gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0;
}
bool IsR2RRelativeIndir() const
@@ -4767,14 +4794,46 @@ struct GenTreeCall final : public GenTree
return (gtCallMoreFlags & GTF_CALL_M_EXPANDED_EARLY) != 0;
}
- void ResetArgInfo();
+ //-----------------------------------------------------------------------------------------
+ // GetIndirectionCellArgKind: Get the kind of indirection cell used by this call.
+ //
+ // Arguments:
+ // None
+ //
+ // Return Value:
+ // The kind (either R2RIndirectionCell or VirtualStubCell),
+ // or NonStandardArgKind::None if this call does not have an indirection cell.
+ //
+ NonStandardArgKind GetIndirectionCellArgKind() const
+ {
+ if (IsVirtualStub())
+ {
+ return NonStandardArgKind::VirtualStubCell;
+ }
- GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags
+#if defined(TARGET_ARMARCH)
+ // For ARM architectures, we always use an indirection cell for R2R calls.
+ if (IsR2RRelativeIndir())
+ {
+ return NonStandardArgKind::R2RIndirectionCell;
+ }
+#elif defined(TARGET_XARCH)
+ // On XARCH we disassemble it from callsite except for tailcalls that need indirection cell.
+ if (IsR2RRelativeIndir() && IsFastTailCall())
+ {
+ return NonStandardArgKind::R2RIndirectionCell;
+ }
+#endif
+
+ return NonStandardArgKind::None;
+ }
- unsigned char gtCallType : 3; // value from the gtCallTypes enumeration
- unsigned char gtReturnType : 5; // exact return type
+ void ResetArgInfo();
- CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available
+ GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags
+ gtCallTypes gtCallType : 3; // value from the gtCallTypes enumeration
+ var_types gtReturnType : 5; // exact return type
+ CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available
union {
// only used for CALLI unmanaged calls (CT_INDIRECT)
diff --git a/src/coreclr/jit/instr.cpp b/src/coreclr/jit/instr.cpp
index d15a17118f9a1..39f885d925fdf 100644
--- a/src/coreclr/jit/instr.cpp
+++ b/src/coreclr/jit/instr.cpp
@@ -2386,41 +2386,6 @@ void CodeGen::instGen_Return(unsigned stkArgSize)
#endif
}
-/*****************************************************************************
- *
- * Emit a MemoryBarrier instruction
- *
- * Note: all MemoryBarriers instructions can be removed by
- * SET COMPlus_JitNoMemoryBarriers=1
- */
-void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
-{
-#ifdef DEBUG
- if (JitConfig.JitNoMemoryBarriers() == 1)
- {
- return;
- }
-#endif // DEBUG
-
-#if defined(TARGET_XARCH)
- // only full barrier needs to be emitted on Xarch
- if (barrierKind != BARRIER_FULL)
- {
- return;
- }
-
- instGen(INS_lock);
- GetEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0);
-#elif defined(TARGET_ARM)
- // ARM has only full barriers, so all barriers need to be emitted as full.
- GetEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf);
-#elif defined(TARGET_ARM64)
- GetEmitter()->emitIns_BARR(INS_dmb, barrierKind == BARRIER_LOAD_ONLY ? INS_BARRIER_ISHLD : INS_BARRIER_ISH);
-#else
-#error "Unknown TARGET"
-#endif
-}
-
/*****************************************************************************
*
* Machine independent way to move a Zero value into a register
diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h
index d9e2b9319ee4c..7999d043b6fc6 100644
--- a/src/coreclr/jit/instr.h
+++ b/src/coreclr/jit/instr.h
@@ -161,6 +161,10 @@ enum insOpts: unsigned
INS_OPTS_ASR,
INS_OPTS_ROR
};
+enum insBarrier : unsigned
+{
+ INS_BARRIER_SY = 15
+};
#elif defined(TARGET_ARM64)
enum insOpts : unsigned
{
@@ -306,8 +310,8 @@ enum emitAttr : unsigned
EA_GCREF = EA_GCREF_FLG | EA_PTRSIZE, /* size == -1 */
EA_BYREF_FLG = 0x100,
EA_BYREF = EA_BYREF_FLG | EA_PTRSIZE, /* size == -2 */
- EA_DSP_RELOC_FLG = 0x200,
- EA_CNS_RELOC_FLG = 0x400,
+ EA_DSP_RELOC_FLG = 0x200, // Is the displacement of the instruction relocatable?
+ EA_CNS_RELOC_FLG = 0x400, // Is the immediate of the instruction relocatable?
};
#define EA_ATTR(x) ((emitAttr)(x))
@@ -315,6 +319,7 @@ enum emitAttr : unsigned
#define EA_SIZE_IN_BYTES(x) ((UNATIVE_OFFSET)(EA_SIZE(x)))
#define EA_SET_SIZE(x, sz) ((emitAttr)((((unsigned)(x)) & ~EA_SIZE_MASK) | (sz)))
#define EA_SET_FLG(x, flg) ((emitAttr)(((unsigned)(x)) | (flg)))
+#define EA_REMOVE_FLG(x, flg) ((emitAttr)(((unsigned)(x)) & ~(flg)))
#define EA_4BYTE_DSP_RELOC (EA_SET_FLG(EA_4BYTE, EA_DSP_RELOC_FLG))
#define EA_PTR_DSP_RELOC (EA_SET_FLG(EA_PTRSIZE, EA_DSP_RELOC_FLG))
#define EA_HANDLE_CNS_RELOC (EA_SET_FLG(EA_PTRSIZE, EA_CNS_RELOC_FLG))
diff --git a/src/coreclr/jit/jit.h b/src/coreclr/jit/jit.h
index e212226851c7c..218871e154fc5 100644
--- a/src/coreclr/jit/jit.h
+++ b/src/coreclr/jit/jit.h
@@ -529,6 +529,9 @@ const bool dspGCtbls = true;
if (JitTls::GetCompiler()->verbose) \
JitTls::GetCompiler()->fgTableDispBasicBlock(b);
#define VERBOSE JitTls::GetCompiler()->verbose
+// Development-time only macros, simplify guards for specified IL methods one wants to debug/add log messages for
+#define ISMETHOD(name) (strcmp(JitTls::GetCompiler()->impInlineRoot()->info.compMethodName, name) == 0)
+#define ISMETHODHASH(hash) (JitTls::GetCompiler()->impInlineRoot()->info.compMethodHash() == hash)
#else // !DEBUG
#define JITDUMP(...)
#define JITDUMPEXEC(x)
diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp
index 06c408395087f..83b9fe3aa01eb 100644
--- a/src/coreclr/jit/loopcloning.cpp
+++ b/src/coreclr/jit/loopcloning.cpp
@@ -534,7 +534,6 @@ void LoopCloneContext::EvaluateConditions(unsigned loopNum, bool* pAllTrue, bool
// Since this will force us to abort loop cloning, there is no need compute an accurate `allTrue`,
// so we can break out of the loop now.
- // REVIEW: it appears we never hit this condition in any test.
break;
}
}
@@ -1009,7 +1008,7 @@ LC_Deref* LC_Deref::Find(JitExpandArrayStack* children, unsigned lcl)
// Operation:
// Inspect the loop cloning optimization candidates and populate the conditions necessary
// for each optimization candidate. Checks if the loop stride is "> 0" if the loop
-// condition is "less than". If the initializer is "var" init then adds condition
+// condition is `<` or `<=`. If the initializer is "var" init then adds condition
// "var >= 0", and if the loop is var limit then, "var >= 0" and "var <= a.len"
// are added to "context". These conditions are checked in the pre-header block
// and the cloning choice is made.
@@ -1026,7 +1025,7 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
LoopDsc* loop = &optLoopTable[loopNum];
JitExpandArrayStack* optInfos = context->GetLoopOptInfo(loopNum);
- if (loop->lpTestOper() == GT_LT)
+ if (GenTree::StaticOperIs(loop->lpTestOper(), GT_LT, GT_LE))
{
// Stride conditions
if (loop->lpIterConst() <= 0)
@@ -1112,6 +1111,21 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
return false;
}
+ // GT_LT loop test: limit <= arrLen
+ // GT_LE loop test: limit < arrLen
+ genTreeOps opLimitCondition;
+ switch (loop->lpTestOper())
+ {
+ case GT_LT:
+ opLimitCondition = GT_LE;
+ break;
+ case GT_LE:
+ opLimitCondition = GT_LT;
+ break;
+ default:
+ unreached();
+ }
+
for (unsigned i = 0; i < optInfos->Size(); ++i)
{
LcOptInfo* optInfo = optInfos->Get(i);
@@ -1119,11 +1133,10 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
{
case LcOptInfo::LcJaggedArray:
{
- // limit <= arrLen
LcJaggedArrayOptInfo* arrIndexInfo = optInfo->AsLcJaggedArrayOptInfo();
LC_Array arrLen(LC_Array::Jagged, &arrIndexInfo->arrIndex, arrIndexInfo->dim, LC_Array::ArrLen);
LC_Ident arrLenIdent = LC_Ident(arrLen);
- LC_Condition cond(GT_LE, LC_Expr(ident), LC_Expr(arrLenIdent));
+ LC_Condition cond(opLimitCondition, LC_Expr(ident), LC_Expr(arrLenIdent));
context->EnsureConditions(loopNum)->Push(cond);
// Ensure that this array must be dereference-able, before executing the actual condition.
@@ -1133,13 +1146,15 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
break;
case LcOptInfo::LcMdArray:
{
- // limit <= mdArrLen
LcMdArrayOptInfo* mdArrInfo = optInfo->AsLcMdArrayOptInfo();
- LC_Condition cond(GT_LE, LC_Expr(ident),
- LC_Expr(LC_Ident(LC_Array(LC_Array::MdArray, mdArrInfo->GetArrIndexForDim(
- getAllocator(CMK_LoopClone)),
- mdArrInfo->dim, LC_Array::None))));
+ LC_Array arrLen(LC_Array(LC_Array::MdArray,
+ mdArrInfo->GetArrIndexForDim(getAllocator(CMK_LoopClone)), mdArrInfo->dim,
+ LC_Array::None));
+ LC_Ident arrLenIdent = LC_Ident(arrLen);
+ LC_Condition cond(opLimitCondition, LC_Expr(ident), LC_Expr(arrLenIdent));
context->EnsureConditions(loopNum)->Push(cond);
+
+ // TODO: ensure array is dereference-able?
}
break;
@@ -1148,11 +1163,14 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
return false;
}
}
+
JITDUMP("Conditions: ");
DBEXEC(verbose, context->PrintConditions(loopNum));
JITDUMP("\n");
+
return true;
}
+
return false;
}
@@ -1398,6 +1416,7 @@ void Compiler::optDebugLogLoopCloning(BasicBlock* block, Statement* insertBefore
void Compiler::optPerformStaticOptimizations(unsigned loopNum, LoopCloneContext* context DEBUGARG(bool dynamicPath))
{
JitExpandArrayStack* optInfos = context->GetLoopOptInfo(loopNum);
+ assert(optInfos != nullptr);
for (unsigned i = 0; i < optInfos->Size(); ++i)
{
LcOptInfo* optInfo = optInfos->Get(i);
@@ -2547,7 +2566,7 @@ PhaseStatus Compiler::optCloneLoops()
{
context.CancelLoopOptInfo(i);
}
- if (allTrue)
+ else if (allTrue)
{
// Perform static optimizations on the fast path since we always
// have to take the cloned path.
diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp
index b588899670d7a..4c06ed0749de1 100644
--- a/src/coreclr/jit/lower.cpp
+++ b/src/coreclr/jit/lower.cpp
@@ -3721,17 +3721,10 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
case IAT_PVALUE:
{
- bool hasIndirectionCell = false;
-#if defined(TARGET_ARMARCH)
- // Skip inserting the indirection node to load the address that is already
- // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the
- // codegen, just load the call target from REG_R2R_INDIRECT_PARAM.
- hasIndirectionCell = call->IsR2RRelativeIndir();
-#elif defined(TARGET_XARCH)
- // For xarch we usually get the indirection cell from the return address,
- // except for fast tailcalls where we do the same as ARM.
- hasIndirectionCell = call->IsR2RRelativeIndir() && call->IsFastTailCall();
-#endif
+ // If we are using an indirection cell for a direct call then apply
+ // an optimization that loads the call target directly from the
+ // indirection cell, instead of duplicating the tree.
+ bool hasIndirectionCell = call->GetIndirectionCellArgKind() != NonStandardArgKind::None;
if (!hasIndirectionCell)
{
@@ -4801,12 +4794,12 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
else
{
bool shouldOptimizeVirtualStubCall = false;
-#if defined(FEATURE_READYTORUN) && defined(TARGET_ARMARCH)
+#if defined(TARGET_ARMARCH) || defined(TARGET_AMD64)
// Skip inserting the indirection node to load the address that is already
- // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the
- // codegen, just load the call target from REG_R2R_INDIRECT_PARAM.
+ // computed in the VSD stub arg register as a hidden parameter. Instead during the
+ // codegen, just load the call target from there.
shouldOptimizeVirtualStubCall = true;
-#endif // FEATURE_READYTORUN && TARGET_ARMARCH
+#endif
if (!shouldOptimizeVirtualStubCall)
{
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index e8b1353a24de0..8e1d5c0147c1e 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -4588,19 +4588,7 @@ void Lowering::ContainCheckIndir(GenTreeIndir* node)
else if (addr->IsCnsIntOrI() && addr->AsIntConCommon()->FitsInAddrBase(comp))
{
// Amd64:
- // We can mark any pc-relative 32-bit addr as containable, except for a direct VSD call address.
- // (i.e. those VSD calls for which stub addr is known during JIT compilation time). In this case,
- // VM requires us to pass stub addr in VirtualStubParam.reg - see LowerVirtualStubCall(). For
- // that reason we cannot mark such an addr as contained. Note that this is not an issue for
- // indirect VSD calls since morphArgs() is explicitly materializing hidden param as a non-standard
- // argument.
- //
- // Workaround:
- // Note that LowerVirtualStubCall() sets addr->GetRegNum() to VirtualStubParam.reg and Lowering::doPhase()
- // sets destination candidates on such nodes and resets addr->GetRegNum() to REG_NA.
- // Ideally we should set a flag on addr nodes that shouldn't be marked as contained
- // (in LowerVirtualStubCall()), but we don't have any GTF_* flags left for that purpose. As a workaround
- // an explicit check is made here.
+ // We can mark any pc-relative 32-bit addr as containable.
//
// On x86, direct VSD is done via a relative branch, and in fact it MUST be contained.
MakeSrcContained(node, addr);
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index a9a78198cb288..55ea93a8fba3a 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -62,9 +62,9 @@ GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeCall:
// The helper call ought to be semantically equivalent to the original node, so preserve its VN.
tree->ChangeOper(GT_CALL, GenTree::PRESERVE_VN);
- GenTreeCall* call = tree->AsCall();
-
+ GenTreeCall* call = tree->AsCall();
call->gtCallType = CT_HELPER;
+ call->gtReturnType = tree->TypeGet();
call->gtCallMethHnd = eeFindHelper(helper);
call->gtCallThisArg = nullptr;
call->gtCallArgs = args;
@@ -10872,6 +10872,72 @@ GenTree* Compiler::fgMorphCommutative(GenTreeOp* tree)
return op1;
}
+//------------------------------------------------------------------------------
+// fgMorphCastedBitwiseOp : Try to simplify "(T)x op (T)y" to "(T)(x op y)".
+//
+// Arguments:
+// tree - node to fold
+//
+// Return Value:
+// A folded GenTree* instance, or nullptr if it couldn't be folded
+GenTree* Compiler::fgMorphCastedBitwiseOp(GenTreeOp* tree)
+{
+ assert(varTypeIsIntegralOrI(tree));
+ assert(tree->OperIs(GT_OR, GT_AND, GT_XOR));
+
+ GenTree* op1 = tree->gtGetOp1();
+ GenTree* op2 = tree->gtGetOp2();
+ genTreeOps oper = tree->OperGet();
+
+ // see whether both ops are casts, with matching to and from types.
+ if (op1->OperIs(GT_CAST) && op2->OperIs(GT_CAST))
+ {
+ // bail if either operand is a checked cast
+ if (op1->gtOverflow() || op2->gtOverflow())
+ {
+ return nullptr;
+ }
+
+ var_types fromType = op1->AsCast()->CastOp()->TypeGet();
+ var_types toType = op1->AsCast()->CastToType();
+ bool isUnsigned = op1->IsUnsigned();
+
+ if ((op2->CastFromType() != fromType) || (op2->CastToType() != toType) || (op2->IsUnsigned() != isUnsigned))
+ {
+ return nullptr;
+ }
+
+ /*
+ // Reuse gentree nodes:
+ //
+ // tree op1
+ // / \ |
+ // op1 op2 ==> tree
+ // | | / \.
+ // x y x y
+ //
+ // (op2 becomes garbage)
+ */
+
+ tree->gtOp1 = op1->AsCast()->CastOp();
+ tree->gtOp2 = op2->AsCast()->CastOp();
+ tree->gtType = fromType;
+
+ op1->gtType = genActualType(toType);
+ op1->AsCast()->gtOp1 = tree;
+ op1->AsCast()->CastToType() = toType;
+ op1->SetAllEffectsFlags(tree);
+ // no need to update isUnsigned
+
+ DEBUG_DESTROY_NODE(op2);
+ INDEBUG(op1->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED);
+
+ return op1;
+ }
+
+ return nullptr;
+}
+
/*****************************************************************************
*
* Transform the given GTK_SMPOP tree for code generation.
@@ -11118,24 +11184,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
return fgMorphSmpOp(tree, mac);
}
- if (opts.OptimizationEnabled() && !optValnumCSE_phase)
- {
- // DIV(NEG(a), C) => DIV(a, NEG(C))
- if (op1->OperIs(GT_NEG) && !op1->gtGetOp1()->IsCnsIntOrI() && op2->IsCnsIntOrI() &&
- !op2->IsIconHandle())
- {
- ssize_t op2Value = op2->AsIntCon()->IconValue();
- if (op2Value != 1 && op2Value != -1) // Div must throw exception for int(long).MinValue / -1.
- {
- tree->AsOp()->gtOp1 = op1->gtGetOp1();
- DEBUG_DESTROY_NODE(op1);
- tree->AsOp()->gtOp2 = gtNewIconNode(-op2Value, op2->TypeGet());
- DEBUG_DESTROY_NODE(op2);
- return fgMorphSmpOp(tree, mac);
- }
- }
- }
-
#ifndef TARGET_64BIT
if (typ == TYP_LONG)
{
@@ -11998,7 +12046,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
break;
case GT_CAST:
- tree = fgOptimizeCast(tree);
+ tree = fgOptimizeCast(tree->AsCast());
if (!tree->OperIsSimple())
{
return tree;
@@ -12516,6 +12564,22 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
op2 = tree->AsOp()->gtOp2;
}
+ if (fgGlobalMorph && varTypeIsIntegralOrI(tree) && tree->OperIs(GT_AND, GT_OR, GT_XOR))
+ {
+ GenTree* result = fgMorphCastedBitwiseOp(tree->AsOp());
+ if (result != nullptr)
+ {
+ assert(result->OperIs(GT_CAST));
+ assert(result->AsOp()->gtOp2 == nullptr);
+ // tree got folded to a unary (cast) op
+ tree = result;
+ oper = tree->OperGet();
+ typ = tree->TypeGet();
+ op1 = tree->AsOp()->gtGetOp1();
+ op2 = nullptr;
+ }
+ }
+
if (varTypeIsIntegralOrI(tree->TypeGet()) && tree->OperIs(GT_ADD, GT_MUL, GT_AND, GT_OR, GT_XOR))
{
GenTree* foldedTree = fgMorphCommutative(tree->AsOp());
@@ -13251,195 +13315,94 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
// Return Value:
// The optimized tree (that can have any shape).
//
-GenTree* Compiler::fgOptimizeCast(GenTree* tree)
+GenTree* Compiler::fgOptimizeCast(GenTreeCast* cast)
{
- GenTree* oper = tree->AsCast()->CastOp();
- var_types srcType = oper->TypeGet();
- var_types dstType = tree->CastToType();
- unsigned dstSize = genTypeSize(dstType);
+ GenTree* src = cast->CastOp();
- if (gtIsActiveCSE_Candidate(tree) || gtIsActiveCSE_Candidate(oper))
+ if (gtIsActiveCSE_Candidate(cast) || gtIsActiveCSE_Candidate(src))
{
- return tree;
+ return cast;
}
- /* See if we can discard the cast */
- if (varTypeIsIntegral(srcType) && varTypeIsIntegral(dstType))
+ // See if we can discard the cast.
+ if (varTypeIsIntegral(cast) && varTypeIsIntegral(src))
{
- if (tree->IsUnsigned() && !varTypeIsUnsigned(srcType))
+ IntegralRange srcRange = IntegralRange::ForNode(src, this);
+ IntegralRange noOvfRange = IntegralRange::ForCastInput(cast);
+
+ if (noOvfRange.Contains(srcRange))
{
- if (varTypeIsSmall(srcType))
+ // Casting between same-sized types is a no-op,
+ // given we have proven this cast cannot overflow.
+ if (genActualType(cast) == genActualType(src))
{
- // Small signed values are automatically sign extended to TYP_INT. If the cast is interpreting the
- // resulting TYP_INT value as unsigned then the "sign" bits end up being "value" bits and srcType
- // must be TYP_UINT, not the original small signed type. Otherwise "conv.ovf.i2.un(i1(-1))" is
- // wrongly treated as a widening conversion from i1 to i2 when in fact it is a narrowing conversion
- // from u4 to i2.
- srcType = genActualType(srcType);
+ return src;
}
- srcType = varTypeToUnsigned(srcType);
- }
+ cast->ClearOverflow();
+ cast->SetAllEffectsFlags(src);
- if (srcType == dstType)
- { // Certainly if they are identical it is pointless
- goto REMOVE_CAST;
+ // Try and see if we can make this cast into a cheaper zero-extending version.
+ if (genActualTypeIsInt(src) && cast->TypeIs(TYP_LONG) && srcRange.IsPositive())
+ {
+ cast->SetUnsigned();
+ }
}
- if (oper->OperGet() == GT_LCL_VAR && varTypeIsSmall(dstType))
+ // For checked casts, we're done.
+ if (cast->gtOverflow())
{
- unsigned varNum = oper->AsLclVarCommon()->GetLclNum();
- LclVarDsc* varDsc = &lvaTable[varNum];
- if (varDsc->TypeGet() == dstType && varDsc->lvNormalizeOnStore())
- {
- goto REMOVE_CAST;
- }
+ return cast;
}
- bool unsignedSrc = varTypeIsUnsigned(srcType);
- bool unsignedDst = varTypeIsUnsigned(dstType);
- bool signsDiffer = (unsignedSrc != unsignedDst);
- unsigned srcSize = genTypeSize(srcType);
+ var_types castToType = cast->CastToType();
- // For same sized casts with
- // the same signs or non-overflow cast we discard them as well
- if (srcSize == dstSize)
+ // For indir-like nodes, we may be able to change their type to satisfy (and discard) the cast.
+ if (varTypeIsSmall(castToType) && (genTypeSize(castToType) == genTypeSize(src)) &&
+ src->OperIs(GT_IND, GT_CLS_VAR, GT_LCL_FLD))
{
- // This should have been handled by "fgMorphExpandCast".
- noway_assert(varTypeIsGC(srcType) == varTypeIsGC(dstType));
+ // We're changing the type here so we need to update the VN;
+ // in other cases we discard the cast without modifying src
+ // so the VN doesn't change.
- if (!signsDiffer)
- {
- goto REMOVE_CAST;
- }
+ src->ChangeType(castToType);
+ src->SetVNsFromNode(cast);
- if (!tree->gtOverflow())
- {
- /* For small type casts, when necessary we force
- the src operand to the dstType and allow the
- implied load from memory to perform the casting */
- if (varTypeIsSmall(srcType))
- {
- switch (oper->gtOper)
- {
- case GT_IND:
- case GT_CLS_VAR:
- case GT_LCL_FLD:
- oper->gtType = dstType;
- // We're changing the type here so we need to update the VN;
- // in other cases we discard the cast without modifying oper
- // so the VN doesn't change.
- oper->SetVNsFromNode(tree);
- goto REMOVE_CAST;
- default:
- break;
- }
- }
- else
- {
- goto REMOVE_CAST;
- }
- }
+ return src;
}
- else if (srcSize < dstSize) // widening cast
- {
- // Keep any long casts
- if (dstSize == sizeof(int))
- {
- // Only keep signed to unsigned widening cast with overflow check
- if (!tree->gtOverflow() || !unsignedDst || unsignedSrc)
- {
- goto REMOVE_CAST;
- }
- }
- // Widening casts from unsigned or to signed can never overflow
+ // Try to narrow the operand of the cast and discard the cast.
+ if (opts.OptEnabled(CLFLG_TREETRANS) && (genTypeSize(src) > genTypeSize(castToType)) &&
+ optNarrowTree(src, src->TypeGet(), castToType, cast->gtVNPair, false))
+ {
+ optNarrowTree(src, src->TypeGet(), castToType, cast->gtVNPair, true);
- if (unsignedSrc || !unsignedDst)
+ // "optNarrowTree" may leave a dead cast behind.
+ if (src->OperIs(GT_CAST) && (src->AsCast()->CastToType() == genActualType(src->AsCast()->CastOp())))
{
- tree->ClearOverflow();
- if ((oper->gtFlags & GTF_EXCEPT) == GTF_EMPTY)
- {
- tree->gtFlags &= ~GTF_EXCEPT;
- }
+ src = src->AsCast()->CastOp();
}
- }
- else // if (srcSize > dstSize)
- {
- // Try to narrow the operand of the cast and discard the cast
- // Note: Do not narrow a cast that is marked as a CSE
- // And do not narrow if the oper is marked as a CSE either
- //
- if (!tree->gtOverflow() && opts.OptEnabled(CLFLG_TREETRANS) &&
- optNarrowTree(oper, srcType, dstType, tree->gtVNPair, false))
- {
- optNarrowTree(oper, srcType, dstType, tree->gtVNPair, true);
- /* If oper is changed into a cast to TYP_INT, or to a GT_NOP, we may need to discard it */
- if (oper->gtOper == GT_CAST && oper->CastToType() == genActualType(oper->CastFromType()))
- {
- oper = oper->AsCast()->CastOp();
- }
- goto REMOVE_CAST;
- }
+ return src;
}
- }
- // Check for two consecutive casts into the same dstType.
- // Also check for consecutive casts to small types.
- if (oper->OperIs(GT_CAST) && !tree->gtOverflow())
- {
- var_types dstCastToType = dstType;
- var_types srcCastToType = oper->CastToType();
- if (dstCastToType == srcCastToType)
- {
- goto REMOVE_CAST;
- }
- // We can take advantage of the implicit zero/sign-extension for
- // small integer types and eliminate some casts.
- if (opts.OptimizationEnabled() && !oper->gtOverflow() && varTypeIsSmall(dstCastToType) &&
- varTypeIsSmall(srcCastToType))
+ // Check for two consecutive casts, we may be able to discard the intermediate one.
+ if (opts.OptimizationEnabled() && src->OperIs(GT_CAST) && !src->gtOverflow())
{
- // Gather some facts about our casts.
- bool srcZeroExtends = varTypeIsUnsigned(srcCastToType);
- bool dstZeroExtends = varTypeIsUnsigned(dstCastToType);
- unsigned srcCastToSize = genTypeSize(srcCastToType);
- unsigned dstCastToSize = genTypeSize(dstCastToType);
-
- // If the previous cast to a smaller type was zero-extending,
- // this cast will also always be zero-extending. Example:
- // CAST(ubyte): 000X => CAST(short): Sign-extend(0X) => 000X.
- if (srcZeroExtends && (dstCastToSize > srcCastToSize))
- {
- dstZeroExtends = true;
- }
+ var_types dstCastToType = castToType;
+ var_types srcCastToType = src->AsCast()->CastToType();
- // Case #1: cast to a smaller or equal in size type.
- // We can discard the intermediate cast. Examples:
- // CAST(short): --XX => CAST(ubyte): 000X.
- // CAST(ushort): 00XX => CAST(short): --XX.
- if (dstCastToSize <= srcCastToSize)
- {
- tree->AsCast()->CastOp() = oper->AsCast()->CastOp();
- DEBUG_DESTROY_NODE(oper);
- }
- // Case #2: cast to a larger type with the same effect.
- // Here we can eliminate the outer cast. Example:
- // CAST(byte): ---X => CAST(short): Sign-extend(-X) => ---X.
- // Example of a sequence where this does not hold:
- // CAST(byte): ---X => CAST(ushort): Zero-extend(-X) => 00-X.
- else if (srcZeroExtends == dstZeroExtends)
+ // CAST(ubyte <- CAST(short <- X)): CAST(ubyte <- X).
+ // CAST(ushort <- CAST(short <- X)): CAST(ushort <- X).
+ if (varTypeIsSmall(srcCastToType) && (genTypeSize(dstCastToType) <= genTypeSize(srcCastToType)))
{
- goto REMOVE_CAST;
+ cast->CastOp() = src->AsCast()->CastOp();
+ DEBUG_DESTROY_NODE(src);
}
}
}
- return tree;
-
-REMOVE_CAST:
- DEBUG_DESTROY_NODE(tree);
- return oper;
+ return cast;
}
//------------------------------------------------------------------------
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index 71c68cd7d78e7..8143582285386 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -1731,8 +1731,7 @@ ValueNum ValueNumStore::VNForByrefCon(target_size_t cnsVal)
return VnForConst(cnsVal, GetByrefCnsMap(), TYP_BYREF);
}
-ValueNum ValueNumStore::VNForCastOper(var_types castToType,
- bool srcIsUnsigned /*=false*/ DEBUGARG(bool printResult /*=true*/))
+ValueNum ValueNumStore::VNForCastOper(var_types castToType, bool srcIsUnsigned)
{
assert(castToType != TYP_STRUCT);
INT32 cnsVal = INT32(castToType) << INT32(VCA_BitCount);
@@ -1745,14 +1744,6 @@ ValueNum ValueNumStore::VNForCastOper(var_types castToType,
}
ValueNum result = VNForIntCon(cnsVal);
-#ifdef DEBUG
- if (printResult && m_pComp->verbose)
- {
- printf(" VNForCastOper(%s%s) is " FMT_VN "\n", varTypeName(castToType), srcIsUnsigned ? ", unsignedSrc" : "",
- result);
- }
-#endif
-
return result;
}
@@ -1768,7 +1759,7 @@ void ValueNumStore::GetCastOperFromVN(ValueNum vn, var_types* pCastToType, bool*
*pSrcIsUnsigned = (value & INT32(VCA_UnsignedSrc)) != 0;
*pCastToType = var_types(value >> INT32(VCA_BitCount));
- assert(VNForCastOper(*pCastToType, *pSrcIsUnsigned DEBUGARG(/*printResult*/ false)) == vn);
+ assert(VNForCastOper(*pCastToType, *pSrcIsUnsigned) == vn);
}
ValueNum ValueNumStore::VNForHandle(ssize_t cnsVal, GenTreeFlags handleFlags)
@@ -5608,6 +5599,10 @@ void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr)
vnDumpSimdType(comp, &funcApp);
break;
#endif // FEATURE_SIMD
+ case VNF_Cast:
+ case VNF_CastOvf:
+ vnDumpCast(comp, vn);
+ break;
default:
printf("%s(", VNFuncName(funcApp.m_func));
@@ -5799,6 +5794,36 @@ void ValueNumStore::vnDumpSimdType(Compiler* comp, VNFuncApp* simdType)
}
#endif // FEATURE_SIMD
+void ValueNumStore::vnDumpCast(Compiler* comp, ValueNum castVN)
+{
+ VNFuncApp cast;
+ bool castFound = GetVNFunc(castVN, &cast);
+ assert(castFound && ((cast.m_func == VNF_Cast) || (cast.m_func == VNF_CastOvf)));
+
+ var_types castToType;
+ bool srcIsUnsigned;
+ GetCastOperFromVN(cast.m_args[1], &castToType, &srcIsUnsigned);
+
+ var_types castFromType = TypeOfVN(cast.m_args[0]);
+ var_types resultType = TypeOfVN(castVN);
+ if (srcIsUnsigned)
+ {
+ castFromType = varTypeToUnsigned(castFromType);
+ }
+
+ comp->vnPrint(cast.m_args[0], 0);
+
+ printf(", ");
+ if ((resultType != castToType) && (castToType != castFromType))
+ {
+ printf("%s <- %s <- %s", varTypeName(resultType), varTypeName(castToType), varTypeName(castFromType));
+ }
+ else
+ {
+ printf("%s <- %s", varTypeName(resultType), varTypeName(castFromType));
+ }
+}
+
#endif // DEBUG
// Static fields, methods.
@@ -9418,38 +9443,41 @@ void Compiler::fgValueNumberCastTree(GenTree* tree)
tree->gtVNPair = vnStore->VNPairForCast(srcVNPair, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
}
-// Compute the normal ValueNumber for a cast operation with no exceptions
+// Compute the ValueNumber for a cast operation
ValueNum ValueNumStore::VNForCast(ValueNum srcVN,
var_types castToType,
var_types castFromType,
- bool srcIsUnsigned /* = false */)
+ bool srcIsUnsigned, /* = false */
+ bool hasOverflowCheck) /* = false */
{
- // The resulting type after performingthe cast is always widened to a supported IL stack size
+ // The resulting type after performing the cast is always widened to a supported IL stack size
var_types resultType = genActualType(castToType);
- // When we're considering actual value returned by a non-checking cast whether or not the source is
- // unsigned does *not* matter for non-widening casts. That is, if we cast an int or a uint to short,
- // we just extract the first two bytes from the source bit pattern, not worrying about the interpretation.
- // The same is true in casting between signed/unsigned types of the same width. Only when we're doing
- // a widening cast do we care about whether the source was unsigned,so we know whether to sign or zero extend it.
- //
- bool srcIsUnsignedNorm = srcIsUnsigned;
- if (genTypeSize(castToType) <= genTypeSize(castFromType))
+ // For integral unchecked casts, only the "int -> long" upcasts use
+ // "srcIsUnsigned", to decide whether to use sign or zero extension.
+ if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType)))
{
- srcIsUnsignedNorm = false;
+ srcIsUnsigned = false;
}
- ValueNum castTypeVN = VNForCastOper(castToType, srcIsUnsigned);
- ValueNum resultVN = VNForFunc(resultType, VNF_Cast, srcVN, castTypeVN);
+ ValueNum srcExcVN;
+ ValueNum srcNormVN;
+ VNUnpackExc(srcVN, &srcNormVN, &srcExcVN);
-#ifdef DEBUG
- if (m_pComp->verbose)
+ VNFunc castFunc = hasOverflowCheck ? VNF_CastOvf : VNF_Cast;
+ ValueNum castTypeVN = VNForCastOper(castToType, srcIsUnsigned);
+ ValueNum resultNormVN = VNForFunc(resultType, castFunc, srcNormVN, castTypeVN);
+ ValueNum resultExcVN = srcExcVN;
+
+ // Add an exception, except if folding took place.
+ // We only fold checked casts that do not overflow.
+ if (hasOverflowCheck && !IsVNConstant(resultNormVN))
{
- printf(" VNForCast(" FMT_VN ", " FMT_VN ") returns ", srcVN, castTypeVN);
- m_pComp->vnPrint(resultVN, 1);
- printf("\n");
+ ValueNum ovfChk = VNForFunc(TYP_REF, VNF_ConvOverflowExc, srcNormVN, castTypeVN);
+ resultExcVN = VNExcSetUnion(VNExcSetSingleton(ovfChk), srcExcVN);
}
-#endif
+
+ ValueNum resultVN = VNWithExc(resultNormVN, resultExcVN);
return resultVN;
}
@@ -9461,60 +9489,12 @@ ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
bool srcIsUnsigned, /* = false */
bool hasOverflowCheck) /* = false */
{
- // The resulting type after performingthe cast is always widened to a supported IL stack size
- var_types resultType = genActualType(castToType);
+ ValueNum srcLibVN = srcVNPair.GetLiberal();
+ ValueNum srcConVN = srcVNPair.GetConservative();
+ ValueNum castLibVN = VNForCast(srcLibVN, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
+ ValueNum castConVN = VNForCast(srcConVN, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
- ValueNumPair castArgVNP;
- ValueNumPair castArgxVNP;
- VNPUnpackExc(srcVNPair, &castArgVNP, &castArgxVNP);
-
- // When we're considering actual value returned by a non-checking cast, (hasOverflowCheck is false)
- // whether or not the source is unsigned does *not* matter for non-widening casts.
- // That is, if we cast an int or a uint to short, we just extract the first two bytes from the source
- // bit pattern, not worrying about the interpretation. The same is true in casting between signed/unsigned
- // types of the same width. Only when we're doing a widening cast do we care about whether the source
- // was unsigned, so we know whether to sign or zero extend it.
- //
- // Important: Casts to floating point cannot be optimized in this fashion. (bug 946768)
- //
- bool srcIsUnsignedNorm = srcIsUnsigned;
- if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType)))
- {
- srcIsUnsignedNorm = false;
- }
-
- VNFunc vnFunc = hasOverflowCheck ? VNF_CastOvf : VNF_Cast;
- ValueNum castTypeVN = VNForCastOper(castToType, srcIsUnsignedNorm);
- ValueNumPair castTypeVNPair(castTypeVN, castTypeVN);
- ValueNumPair castNormRes = VNPairForFunc(resultType, vnFunc, castArgVNP, castTypeVNPair);
-
- ValueNumPair resultVNP = VNPWithExc(castNormRes, castArgxVNP);
-
- // If we have a check for overflow, add the exception information.
- if (hasOverflowCheck)
- {
- ValueNumPair excSet = ValueNumStore::VNPForEmptyExcSet();
-
- ValueNumKind vnKinds[2] = {VNK_Liberal, VNK_Conservative};
- for (ValueNumKind vnKind : vnKinds)
- {
- // Do not add exceptions for folded casts.
- // We only fold checked casts that do not overflow.
- if (IsVNConstant(castNormRes.Get(vnKind)))
- {
- continue;
- }
-
- ValueNum ovfChk =
- VNForFunc(TYP_REF, VNF_ConvOverflowExc, castArgVNP.Get(vnKind), castTypeVNPair.Get(vnKind));
- excSet.Set(vnKind, VNExcSetSingleton(ovfChk));
- }
-
- excSet = VNPExcSetUnion(excSet, castArgxVNP);
- resultVNP = VNPWithExc(castNormRes, excSet);
- }
-
- return resultVNP;
+ return {castLibVN, castConVN};
}
void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc)
@@ -9789,6 +9769,81 @@ void Compiler::fgValueNumberCall(GenTreeCall* call)
}
}
+void Compiler::fgValueNumberCastHelper(GenTreeCall* call)
+{
+ CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
+ var_types castToType = TYP_UNDEF;
+ var_types castFromType = TYP_UNDEF;
+ bool srcIsUnsigned = false;
+ bool hasOverflowCheck = false;
+
+ switch (helpFunc)
+ {
+ case CORINFO_HELP_LNG2DBL:
+ castToType = TYP_DOUBLE;
+ castFromType = TYP_LONG;
+ break;
+
+ case CORINFO_HELP_ULNG2DBL:
+ castToType = TYP_DOUBLE;
+ castFromType = TYP_LONG;
+ srcIsUnsigned = true;
+ break;
+
+ case CORINFO_HELP_DBL2INT:
+ castToType = TYP_INT;
+ castFromType = TYP_DOUBLE;
+ break;
+
+ case CORINFO_HELP_DBL2INT_OVF:
+ castToType = TYP_INT;
+ castFromType = TYP_DOUBLE;
+ hasOverflowCheck = true;
+ break;
+
+ case CORINFO_HELP_DBL2LNG:
+ castToType = TYP_LONG;
+ castFromType = TYP_DOUBLE;
+ break;
+
+ case CORINFO_HELP_DBL2LNG_OVF:
+ castToType = TYP_LONG;
+ castFromType = TYP_DOUBLE;
+ hasOverflowCheck = true;
+ break;
+
+ case CORINFO_HELP_DBL2UINT:
+ castToType = TYP_UINT;
+ castFromType = TYP_DOUBLE;
+ break;
+
+ case CORINFO_HELP_DBL2UINT_OVF:
+ castToType = TYP_UINT;
+ castFromType = TYP_DOUBLE;
+ hasOverflowCheck = true;
+ break;
+
+ case CORINFO_HELP_DBL2ULNG:
+ castToType = TYP_ULONG;
+ castFromType = TYP_DOUBLE;
+ break;
+
+ case CORINFO_HELP_DBL2ULNG_OVF:
+ castToType = TYP_ULONG;
+ castFromType = TYP_DOUBLE;
+ hasOverflowCheck = true;
+ break;
+
+ default:
+ unreached();
+ }
+
+ ValueNumPair argVNP = call->gtCallArgs->GetNode()->gtVNPair;
+ ValueNumPair castVNP = vnStore->VNPairForCast(argVNP, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
+
+ call->SetVNs(castVNP);
+}
+
VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
{
assert(s_helperCallProperties.IsPure(helpFunc) || s_helperCallProperties.IsAllocator(helpFunc));
@@ -9819,12 +9874,14 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
vnf = VNFunc(GT_RSZ);
break;
case CORINFO_HELP_LMUL:
- case CORINFO_HELP_LMUL_OVF:
vnf = VNFunc(GT_MUL);
break;
+ case CORINFO_HELP_LMUL_OVF:
+ vnf = VNF_MUL_OVF;
+ break;
case CORINFO_HELP_ULMUL_OVF:
- vnf = VNFunc(GT_MUL);
- break; // Is this the right thing?
+ vnf = VNF_MUL_UN_OVF;
+ break;
case CORINFO_HELP_LDIV:
vnf = VNFunc(GT_DIV);
break;
@@ -9837,37 +9894,6 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
case CORINFO_HELP_ULMOD:
vnf = VNFunc(GT_UMOD);
break;
-
- case CORINFO_HELP_LNG2DBL:
- vnf = VNF_Lng2Dbl;
- break;
- case CORINFO_HELP_ULNG2DBL:
- vnf = VNF_ULng2Dbl;
- break;
- case CORINFO_HELP_DBL2INT:
- vnf = VNF_Dbl2Int;
- break;
- case CORINFO_HELP_DBL2INT_OVF:
- vnf = VNF_Dbl2IntOvf;
- break;
- case CORINFO_HELP_DBL2LNG:
- vnf = VNF_Dbl2Lng;
- break;
- case CORINFO_HELP_DBL2LNG_OVF:
- vnf = VNF_Dbl2LngOvf;
- break;
- case CORINFO_HELP_DBL2UINT:
- vnf = VNF_Dbl2UInt;
- break;
- case CORINFO_HELP_DBL2UINT_OVF:
- vnf = VNF_Dbl2UIntOvf;
- break;
- case CORINFO_HELP_DBL2ULNG:
- vnf = VNF_Dbl2ULng;
- break;
- case CORINFO_HELP_DBL2ULNG_OVF:
- vnf = VNF_Dbl2ULngOvf;
- break;
case CORINFO_HELP_FLTREM:
vnf = VNFunc(GT_MOD);
break;
@@ -10072,12 +10098,32 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
{
- CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
- bool pure = s_helperCallProperties.IsPure(helpFunc);
- bool isAlloc = s_helperCallProperties.IsAllocator(helpFunc);
- bool modHeap = s_helperCallProperties.MutatesHeap(helpFunc);
- bool mayRunCctor = s_helperCallProperties.MayRunCctor(helpFunc);
- bool noThrow = s_helperCallProperties.NoThrow(helpFunc);
+ CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
+
+ switch (helpFunc)
+ {
+ case CORINFO_HELP_LNG2DBL:
+ case CORINFO_HELP_ULNG2DBL:
+ case CORINFO_HELP_DBL2INT:
+ case CORINFO_HELP_DBL2INT_OVF:
+ case CORINFO_HELP_DBL2LNG:
+ case CORINFO_HELP_DBL2LNG_OVF:
+ case CORINFO_HELP_DBL2UINT:
+ case CORINFO_HELP_DBL2UINT_OVF:
+ case CORINFO_HELP_DBL2ULNG:
+ case CORINFO_HELP_DBL2ULNG_OVF:
+ fgValueNumberCastHelper(call);
+ return false;
+
+ default:
+ break;
+ }
+
+ bool pure = s_helperCallProperties.IsPure(helpFunc);
+ bool isAlloc = s_helperCallProperties.IsAllocator(helpFunc);
+ bool modHeap = s_helperCallProperties.MutatesHeap(helpFunc);
+ bool mayRunCctor = s_helperCallProperties.MayRunCctor(helpFunc);
+ bool noThrow = s_helperCallProperties.NoThrow(helpFunc);
ValueNumPair vnpExc = ValueNumStore::VNPForEmptyExcSet();
@@ -10843,7 +10889,6 @@ void Compiler::vnpPrint(ValueNumPair vnp, unsigned level)
void Compiler::vnPrint(ValueNum vn, unsigned level)
{
-
if (ValueNumStore::isReservedVN(vn))
{
printf(ValueNumStore::reservedName(vn));
diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h
index b64d19993fa72..d09bd3197e91c 100644
--- a/src/coreclr/jit/valuenum.h
+++ b/src/coreclr/jit/valuenum.h
@@ -291,7 +291,7 @@ class ValueNumStore
// Packs information about the cast into an integer constant represented by the returned value number,
// to be used as the second operand of VNF_Cast & VNF_CastOvf.
- ValueNum VNForCastOper(var_types castToType, bool srcIsUnsigned = false DEBUGARG(bool printResult = true));
+ ValueNum VNForCastOper(var_types castToType, bool srcIsUnsigned);
// Unpacks the information stored by VNForCastOper in the constant represented by the value number.
void GetCastOperFromVN(ValueNum vn, var_types* pCastToType, bool* pSrcIsUnsigned);
@@ -556,8 +556,12 @@ class ValueNumStore
rhs.GetConservative(), indType, block));
}
- // Compute the normal ValueNumber for a cast with no exceptions
- ValueNum VNForCast(ValueNum srcVN, var_types castToType, var_types castFromType, bool srcIsUnsigned = false);
+ // Compute the ValueNumber for a cast
+ ValueNum VNForCast(ValueNum srcVN,
+ var_types castToType,
+ var_types castFromType,
+ bool srcIsUnsigned = false,
+ bool hasOverflowCheck = false);
// Compute the ValueNumberPair for a cast
ValueNumPair VNPairForCast(ValueNumPair srcVNPair,
@@ -898,6 +902,10 @@ class ValueNumStore
void vnDumpSimdType(Compiler* comp, VNFuncApp* simdType);
#endif // FEATURE_SIMD
+ // Requires "castVN" to represent VNF_Cast or VNF_CastOvf.
+ // Prints the cast's representation mirroring GT_CAST's dump format.
+ void vnDumpCast(Compiler* comp, ValueNum castVN);
+
// Returns the string name of "vnf".
static const char* VNFuncName(VNFunc vnf);
// Used in the implementation of the above.
diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h
index 448f40e382146..7665770881bcd 100644
--- a/src/coreclr/jit/valuenumfuncs.h
+++ b/src/coreclr/jit/valuenumfuncs.h
@@ -69,16 +69,6 @@ ValueNumFuncDef(InvalidCastExc, 2, false, false, false) // CastClass check,
ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false) // Raises Integer overflow when Arg 0 is negative
ValueNumFuncDef(HelperMultipleExc, 0, false, false, false) // Represents one or more different exceptions that could be thrown by a Jit Helper method
-ValueNumFuncDef(Lng2Dbl, 1, false, false, false)
-ValueNumFuncDef(ULng2Dbl, 1, false, false, false)
-ValueNumFuncDef(Dbl2Int, 1, false, false, false)
-ValueNumFuncDef(Dbl2UInt, 1, false, false, false)
-ValueNumFuncDef(Dbl2Lng, 1, false, false, false)
-ValueNumFuncDef(Dbl2ULng, 1, false, false, false)
-ValueNumFuncDef(Dbl2IntOvf, 1, false, false, false)
-ValueNumFuncDef(Dbl2UIntOvf, 1, false, false, false)
-ValueNumFuncDef(Dbl2LngOvf, 1, false, false, false)
-ValueNumFuncDef(Dbl2ULngOvf, 1, false, false, false)
ValueNumFuncDef(FltRound, 1, false, false, false)
ValueNumFuncDef(DblRound, 1, false, false, false)
diff --git a/src/coreclr/scripts/antigen_run.py b/src/coreclr/scripts/antigen_run.py
index e97196debeedf..96146005906d9 100644
--- a/src/coreclr/scripts/antigen_run.py
+++ b/src/coreclr/scripts/antigen_run.py
@@ -20,8 +20,7 @@
from os.path import getsize
import os
from coreclr_arguments import *
-from superpmi_setup import run_command
-from superpmi import TempDir
+from azdo_pipelines_util import run_command, TempDir
parser = argparse.ArgumentParser(description="description")
@@ -30,6 +29,7 @@
parser.add_argument("-output_directory", help="Path to output directory")
parser.add_argument("-partition", help="Partition name")
parser.add_argument("-core_root", help="path to CORE_ROOT directory")
+parser.add_argument("-run_duration", help="Run duration in minutes")
is_windows = platform.system() == "Windows"
@@ -71,6 +71,10 @@ def setup_args(args):
lambda core_root: os.path.isdir(core_root),
"core_root doesn't exist")
+ coreclr_args.verify(args,
+ "run_duration",
+ lambda unused: True,
+ "Unable to set run_duration")
return coreclr_args
@@ -164,7 +168,16 @@ def sorter_by_size(pair):
except PermissionError as pe_error:
print('Ignoring PermissionError: {0}'.format(pe_error))
+ src_antigen_log = os.path.join(issues_directory, get_antigen_filename(tag_name))
+ dst_antigen_log = os.path.join(upload_directory, get_antigen_filename(tag_name))
+ print("Copying {} to {}".format(src_antigen_log, dst_antigen_log))
+ try:
+ shutil.copy2(src_antigen_log, dst_antigen_log)
+ except PermissionError as pe_error:
+ print('Ignoring PermissionError: {0}'.format(pe_error))
+def get_antigen_filename(tag_name):
+ return "Antigen-{}.log".format(tag_name)
def main(main_args):
"""Main entrypoint
@@ -179,7 +192,9 @@ def main(main_args):
core_root = coreclr_args.core_root
tag_name = "{}-{}".format(coreclr_args.run_configuration, coreclr_args.partition)
output_directory = coreclr_args.output_directory
- run_duration = 120 # Run for 2 hours
+ run_duration = coreclr_args.run_duration
+ if not run_duration:
+ run_duration = 60
path_to_corerun = os.path.join(core_root, "corerun")
path_to_tool = os.path.join(antigen_directory, "Antigen")
@@ -187,13 +202,17 @@ def main(main_args):
path_to_corerun += ".exe"
path_to_tool += ".exe"
- # Run tool such that issues are placed in a temp folder
- with TempDir() as temp_location:
- run_command([path_to_tool, "-c", path_to_corerun, "-o", temp_location, "-d", str(run_duration)], _exit_on_fail=True, _long_running= True)
-
- # Copy issues for upload
- print("Copying issues to " + output_directory)
- copy_issues(temp_location, output_directory, tag_name)
+ try:
+ # Run tool such that issues are placed in a temp folder
+ with TempDir() as temp_location:
+ antigen_log = path.join(temp_location, get_antigen_filename(tag_name))
+ run_command([path_to_tool, "-c", path_to_corerun, "-o", temp_location, "-d", str(run_duration)], _exit_on_fail=True, _output_file= antigen_log)
+
+ # Copy issues for upload
+ print("Copying issues to " + output_directory)
+ copy_issues(temp_location, output_directory, tag_name)
+ except PermissionError as pe:
+ print("Got error: %s", pe)
if __name__ == "__main__":
args = parser.parse_args()
diff --git a/src/coreclr/scripts/antigen_setup.py b/src/coreclr/scripts/antigen_setup.py
index d82df7d9338a8..8026bcb93a93f 100644
--- a/src/coreclr/scripts/antigen_setup.py
+++ b/src/coreclr/scripts/antigen_setup.py
@@ -19,8 +19,7 @@
import os
from os import listdir
from coreclr_arguments import *
-from superpmi_setup import run_command, copy_directory, set_pipeline_variable
-from superpmi import ChangeDir, TempDir
+from azdo_pipelines_util import run_command, copy_directory, set_pipeline_variable, ChangeDir, TempDir
import tempfile
parser = argparse.ArgumentParser(description="description")
@@ -88,7 +87,6 @@ def main(main_args):
helix_source_prefix = "official"
creator = ""
- ci = True
# create exploratory directory
print('Copying {} -> {}'.format(scripts_src_directory, coreroot_dst_directory))
diff --git a/src/coreclr/scripts/azdo_pipelines_util.py b/src/coreclr/scripts/azdo_pipelines_util.py
new file mode 100644
index 0000000000000..cabbcf8e68607
--- /dev/null
+++ b/src/coreclr/scripts/azdo_pipelines_util.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python3
+#
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+#
+# Title : azdo_pipelines_util.py
+#
+# Notes:
+#
+# Utility functions used by Python scripts involved with Azure DevOps Pipelines
+# setup.
+#
+################################################################################
+################################################################################
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _output_file=None):
+ """ Runs the command.
+
+ Args:
+ command_to_run ([string]): Command to run along with arguments.
+ _cwd (string): Current working directory.
+ _exit_on_fail (bool): If it should exit on failure.
+ Returns:
+ (string, string, int): Returns a tuple of stdout, stderr, and command return code if _output_file= None
+ Otherwise stdout, stderr are empty.
+ """
+ print("Running: " + " ".join(command_to_run))
+ command_stdout = ""
+ command_stderr = ""
+ return_code = 1
+
+ output_type = subprocess.STDOUT if _output_file else subprocess.PIPE
+ with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=output_type, cwd=_cwd) as proc:
+
+ # For long running command, continuously print the output
+ if _output_file:
+ while True:
+ with open(_output_file, 'a') as of:
+ output = proc.stdout.readline()
+ if proc.poll() is not None:
+ break
+ if output:
+ of.write(output.strip().decode("utf-8") + "\n")
+ else:
+ command_stdout, command_stderr = proc.communicate()
+ if len(command_stdout) > 0:
+ print(command_stdout.decode("utf-8"))
+ if len(command_stderr) > 0:
+ print(command_stderr.decode("utf-8"))
+
+ return_code = proc.returncode
+ if _exit_on_fail and return_code != 0:
+ print("Command failed. Exiting.")
+ sys.exit(1)
+ return command_stdout, command_stderr, return_code
+
+
+def copy_directory(src_path, dst_path, verbose_output=True, match_func=lambda path: True):
+ """Copies directory in 'src_path' to 'dst_path' maintaining the directory
+ structure. https://docs.python.org/3.5/library/shutil.html#shutil.copytree can't
+ be used in this case because it expects the destination directory should not
+ exist, however we do call copy_directory() to copy files to same destination directory.
+
+ Args:
+ src_path (string): Path of source directory that need to be copied.
+ dst_path (string): Path where directory should be copied.
+ verbose_output (bool): True to print every copy or skipped file.
+ match_func (str -> bool) : Criteria function determining if a file is copied.
+ """
+ if not os.path.exists(dst_path):
+ os.makedirs(dst_path)
+ for item in os.listdir(src_path):
+ src_item = os.path.join(src_path, item)
+ dst_item = os.path.join(dst_path, item)
+ if os.path.isdir(src_item):
+ copy_directory(src_item, dst_item, verbose_output, match_func)
+ else:
+ try:
+ if match_func(src_item):
+ if verbose_output:
+ print("> copy {0} => {1}".format(src_item, dst_item))
+ try:
+ shutil.copy2(src_item, dst_item)
+ except PermissionError as pe_error:
+ print('Ignoring PermissionError: {0}'.format(pe_error))
+ else:
+ if verbose_output:
+ print("> skipping {0}".format(src_item))
+ except UnicodeEncodeError:
+ if verbose_output:
+ print("> Got UnicodeEncodeError")
+
+
+def copy_files(src_path, dst_path, file_names):
+ """Copy files from 'file_names' list from 'src_path' to 'dst_path'.
+ It retains the original directory structure of src_path.
+
+ Args:
+ src_path (string): Source directory from where files are copied.
+ dst_path (string): Destination directory where files to be copied.
+ file_names ([string]): List of full path file names to be copied.
+ """
+
+ print('### Copying below files from {0} to {1}:'.format(src_path, dst_path))
+ print('')
+ print(os.linesep.join(file_names))
+ for f in file_names:
+ # Create same structure in dst so we don't clobber same files names present in different directories
+ dst_path_of_file = f.replace(src_path, dst_path)
+
+ dst_directory = os.path.dirname(dst_path_of_file)
+ if not os.path.exists(dst_directory):
+ os.makedirs(dst_directory)
+ try:
+ shutil.copy2(f, dst_path_of_file)
+ except PermissionError as pe_error:
+ print('Ignoring PermissionError: {0}'.format(pe_error))
+
+
+def set_pipeline_variable(name, value):
+ """ This method sets pipeline variable.
+
+ Args:
+ name (string): Name of the variable.
+ value (string): Value of the variable.
+ """
+ define_variable_format = "##vso[task.setvariable variable={0}]{1}"
+ print("{0} -> {1}".format(name, value)) # logging
+ print(define_variable_format.format(name, value)) # set variable
+
+
+class TempDir:
+ """ Class to create a temporary working directory, or use one that is passed as an argument.
+
+ Use with: "with TempDir() as temp_dir" to change to that directory and then automatically
+ change back to the original working directory afterwards and remove the temporary
+ directory and its contents (if skip_cleanup is False).
+ """
+
+ def __init__(self, path=None, skip_cleanup=False):
+ self.mydir = tempfile.mkdtemp() if path is None else path
+ self.cwd = None
+ self._skip_cleanup = skip_cleanup
+
+ def __enter__(self):
+ self.cwd = os.getcwd()
+ os.chdir(self.mydir)
+ return self.mydir
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ os.chdir(self.cwd)
+ if not self._skip_cleanup:
+ shutil.rmtree(self.mydir)
+
+
+class ChangeDir:
+ """ Class to temporarily change to a given directory. Use with "with".
+ """
+
+ def __init__(self, mydir):
+ self.mydir = mydir
+ self.cwd = None
+
+ def __enter__(self):
+ self.cwd = os.getcwd()
+ os.chdir(self.mydir)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ os.chdir(self.cwd)
\ No newline at end of file
diff --git a/src/coreclr/scripts/exploratory.proj b/src/coreclr/scripts/exploratory.proj
index 2c347c5a0cbff..8b24de9bdfb52 100644
--- a/src/coreclr/scripts/exploratory.proj
+++ b/src/coreclr/scripts/exploratory.proj
@@ -28,7 +28,6 @@
false
false
- 2:30
$(_Creator)
$(_HelixAccessToken)
$(_HelixBuild)
@@ -37,6 +36,16 @@
$(_HelixType)
+
+
+ 3:15
+ 180
+
+
+ 1:15
+ 60
+
+
@@ -48,7 +57,7 @@
@(HelixPreCommand)
@(HelixPostCommand)
- $(Python) $(CoreRoot)$(FileSeparatorChar)antigen_run.py -run_configuration $(RunConfiguration) -output_directory $(OutputDirectory) -antigen_directory $(ToolPath) -core_root $(CoreRoot)
+ $(Python) $(CoreRoot)$(FileSeparatorChar)antigen_run.py -run_configuration $(RunConfiguration) -output_directory $(OutputDirectory) -antigen_directory $(ToolPath) -core_root $(CoreRoot) -run_duration $(RunDuration)
@@ -70,7 +79,7 @@
$(WorkItemDirectory)
$(WorkItemCommand) -partition %(PartitionName)
$(WorkItemTimeout)
- AllIssues-$(RunConfiguration)-%(PartitionName).zip;issues-summary-$(RunConfiguration)-%(PartitionName).txt
+ AllIssues-$(RunConfiguration)-%(PartitionName).zip;issues-summary-$(RunConfiguration)-%(PartitionName).txt;Antigen-$(RunConfiguration)-%(PartitionName).log
diff --git a/src/coreclr/scripts/superpmi.proj b/src/coreclr/scripts/superpmi-collect.proj
similarity index 100%
rename from src/coreclr/scripts/superpmi.proj
rename to src/coreclr/scripts/superpmi-collect.proj
diff --git a/src/coreclr/scripts/superpmi-replay.proj b/src/coreclr/scripts/superpmi-replay.proj
index a44bc0889c255..e76a4a3d810e5 100644
--- a/src/coreclr/scripts/superpmi-replay.proj
+++ b/src/coreclr/scripts/superpmi-replay.proj
@@ -30,10 +30,19 @@
%HELIX_WORKITEM_UPLOAD_ROOT%
$(BUILD_SOURCESDIRECTORY)\artifacts\helixresults
- $(Python) $(ProductDirectory)\superpmi-replay.py -jit_directory $(ProductDirectory)
+ $(Python) $(ProductDirectory)\superpmi_replay.py -jit_directory $(ProductDirectory)
+ 3:15
+
+
+
false
false
- 5:00
+ $(_Creator)
+ $(_HelixAccessToken)
+ $(_HelixBuild)
+ $(_HelixSource)
+ $(_HelixTargetQueues)
+ $(_HelixType)
diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py
index 4b502f0bffa4f..7618c11480ec0 100755
--- a/src/coreclr/scripts/superpmi.py
+++ b/src/coreclr/scripts/superpmi.py
@@ -18,6 +18,7 @@
import argparse
import asyncio
+import csv
import datetime
import locale
import logging
@@ -800,6 +801,22 @@ def is_url(path):
# If it doesn't look like an URL, treat it like a file, possibly a UNC file.
return path.lower().startswith("http:") or path.lower().startswith("https:")
+def read_csv_metrics(path):
+ """ Read a metrics summary file produced by superpmi, and return the single row containing the information as a dictionary.
+
+ Args:
+ path (str) : path to .csv file
+
+ Returns:
+ A dictionary with each metric
+ """
+
+ with open(path) as csv_file:
+ reader = csv.DictReader(csv_file)
+ for row in reader:
+ return row
+
+ return None
################################################################################
# Helper classes
@@ -1800,6 +1817,9 @@ def replay_with_asm_diffs(self):
fail_mcl_file = os.path.join(temp_location, os.path.basename(mch_file) + "_fail.mcl")
diff_mcl_file = os.path.join(temp_location, os.path.basename(mch_file) + "_diff.mcl")
+ base_metrics_summary_file = os.path.join(temp_location, os.path.basename(mch_file) + "_base_metrics.csv")
+ diff_metrics_summary_file = os.path.join(temp_location, os.path.basename(mch_file) + "_diff_metrics.csv")
+
# If the user passed -temp_dir, we skip the SuperPMI replay process,
# and rely on what we find from a previous run.
if self.coreclr_args.temp_dir is not None:
@@ -1810,7 +1830,9 @@ def replay_with_asm_diffs(self):
"-v", "ewmi", # display errors, warnings, missing, jit info
"-f", fail_mcl_file, # Failing mc List
"-diffMCList", diff_mcl_file, # Create all of the diffs in an mcl file
- "-r", os.path.join(temp_location, "repro") # Repro name, create .mc repro files
+ "-r", os.path.join(temp_location, "repro"), # Repro name, create .mc repro files
+ "-baseMetricsSummary", base_metrics_summary_file, # Create summary of metrics we can use to get total code size impact
+ "-diffMetricsSummary", diff_metrics_summary_file,
]
flags += altjit_asm_diffs_flags
flags += base_option_flags
@@ -1839,7 +1861,7 @@ def replay_with_asm_diffs(self):
return_code = run_and_log(command)
print_superpmi_failure_code(return_code, self.coreclr_args)
if return_code == 0:
- logging.info("Clean SuperPMI replay")
+ logging.info("Clean SuperPMI diff")
else:
result = False
# Don't report as replay failure asm diffs (return code 2) or missing data (return code 3).
@@ -1961,6 +1983,17 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
logging.debug(item)
logging.debug("")
+ base_metrics = read_csv_metrics(base_metrics_summary_file)
+ diff_metrics = read_csv_metrics(diff_metrics_summary_file)
+
+ if base_metrics is not None and "Code bytes" in base_metrics and diff_metrics is not None and "Code bytes" in diff_metrics:
+ base_bytes = int(base_metrics["Code bytes"])
+ diff_bytes = int(diff_metrics["Code bytes"])
+ logging.info("Total Code bytes of base: {}".format(base_bytes))
+ logging.info("Total Code bytes of diff: {}".format(diff_bytes))
+ delta_bytes = diff_bytes - base_bytes
+ logging.info("Total Code bytes of delta: {} ({:.2%} of base)".format(delta_bytes, delta_bytes / base_bytes))
+
try:
current_text_diff = text_differences.get_nowait()
except:
@@ -1985,6 +2018,9 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
command = [ jit_analyze_path, "--md", md_summary_file, "-r", "--base", base_asm_location, "--diff", diff_asm_location ]
if self.coreclr_args.metrics:
command += [ "--metrics", ",".join(self.coreclr_args.metrics) ]
+ elif base_bytes is not None and diff_bytes is not None:
+ command += [ "--override-total-base-metric", str(base_bytes), "--override-total-diff-metric", str(diff_bytes) ]
+
run_and_log(command, logging.INFO)
ran_jit_analyze = True
@@ -2015,6 +2051,14 @@ async def create_one_artifact(jit_path: str, location: str, flags) -> str:
os.remove(fail_mcl_file)
fail_mcl_file = None
+ if os.path.isfile(base_metrics_summary_file):
+ os.remove(base_metrics_summary_file)
+ base_metrics_summary_file = None
+
+ if os.path.isfile(diff_metrics_summary_file):
+ os.remove(diff_metrics_summary_file)
+ diff_metrics_summary_file = None
+
################################################################################################ end of for mch_file in self.mch_files
# Report the overall results summary of the asmdiffs run
diff --git a/src/coreclr/scripts/superpmi_benchmarks.py b/src/coreclr/scripts/superpmi_benchmarks.py
index 6981fa22cbba0..d96f06b7e9866 100644
--- a/src/coreclr/scripts/superpmi_benchmarks.py
+++ b/src/coreclr/scripts/superpmi_benchmarks.py
@@ -20,8 +20,7 @@
from os.path import isfile
from shutil import copyfile
from coreclr_arguments import *
-from superpmi import ChangeDir, TempDir
-from superpmi_setup import run_command
+from azdo_pipelines_util import run_command, ChangeDir, TempDir
# Start of parser object creation.
is_windows = platform.system() == "Windows"
diff --git a/src/coreclr/scripts/superpmi_setup.py b/src/coreclr/scripts/superpmi_collect_setup.py
similarity index 75%
rename from src/coreclr/scripts/superpmi_setup.py
rename to src/coreclr/scripts/superpmi_collect_setup.py
index 9ecec3bd9dd23..db49ff5b70d19 100644
--- a/src/coreclr/scripts/superpmi_setup.py
+++ b/src/coreclr/scripts/superpmi_collect_setup.py
@@ -3,8 +3,7 @@
# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the MIT license.
#
-##
-# Title : superpmi_setup.py
+# Title : superpmi_collect_setup.py
#
# Notes:
#
@@ -21,7 +20,7 @@
# `CORE_ROOT` folder and this script will copy `max_size` bytes of those files under `payload/libraries/0/binaries`,
# `payload/libraries/1/binaries` and so forth.
# 4. Lastly, it sets the pipeline variables.
-
+#
# Below are the helix queues it sets depending on the OS/architecture:
# | Arch | windows | Linux |
# |-------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------|
@@ -29,20 +28,17 @@
# | x64 | Windows.10.Amd64.X86 | Ubuntu.1804.Amd64 |
# | arm | - | (Ubuntu.1804.Arm32)Ubuntu.1804.Armarch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm32v7-bfcd90a-20200121150440 |
# | arm64 | Windows.10.Arm64 | (Ubuntu.1804.Arm64)Ubuntu.1804.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8-20210531091519-97d8652 |
+#
################################################################################
################################################################################
-
import argparse
-import shutil
+import os
import stat
-import subprocess
-import tempfile
-from os import linesep, listdir, path, walk
-from os.path import isfile, join, getsize
from coreclr_arguments import *
-from superpmi import ChangeDir
+from azdo_pipelines_util import run_command, copy_directory, copy_files, set_pipeline_variable, ChangeDir, TempDir
+
# Start of parser object creation.
@@ -251,7 +247,7 @@ def sorter_by_size(pair):
filename_with_size = []
- for file_path, dirs, files in walk(src_directory, topdown=True):
+ for file_path, dirs, files in os.walk(src_directory, topdown=True):
# Credit: https://stackoverflow.com/a/19859907
dirs[:] = [d for d in dirs if d not in exclude_directories]
for name in files:
@@ -259,14 +255,14 @@ def sorter_by_size(pair):
exclude_files_lower = [filename.lower() for filename in exclude_files]
if name.lower() in exclude_files_lower:
continue
- curr_file_path = path.join(file_path, name)
+ curr_file_path = os.path.join(file_path, name)
- if not isfile(curr_file_path):
+ if not os.path.isfile(curr_file_path):
continue
if not name.endswith(".dll") and not name.endswith(".exe"):
continue
- size = getsize(curr_file_path)
+ size = os.path.getsize(curr_file_path)
filename_with_size.append((curr_file_path, size))
return sorter_by_size(filename_with_size)
@@ -312,109 +308,6 @@ def first_fit(sorted_by_size, max_size):
return partitions
-def run_command(command_to_run, _cwd=None, _exit_on_fail=False, _long_running=False):
- """ Runs the command.
-
- Args:
- command_to_run ([string]): Command to run along with arguments.
- _cwd (string): Current working directory.
- _exit_on_fail (bool): If it should exit on failure.
- Returns:
- (string, string, int): Returns a tuple of stdout, stderr, and command return code if _long_running= False
- Otherwise stdout, stderr are empty.
- """
- print("Running: " + " ".join(command_to_run))
- command_stdout = ""
- command_stderr = ""
- return_code = 1
-
- output_type = subprocess.STDOUT if _long_running else subprocess.PIPE
- with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=output_type, cwd=_cwd) as proc:
-
- # For long running command, continuosly print the output
- if _long_running:
- while True:
- output = proc.stdout.readline()
- if proc.poll() is not None:
- break
- if output:
- print(output.strip().decode("utf-8"))
- else:
- command_stdout, command_stderr = proc.communicate()
- if len(command_stdout) > 0:
- print(command_stdout.decode("utf-8"))
- if len(command_stderr) > 0:
- print(command_stderr.decode("utf-8"))
-
- return_code = proc.returncode
- if _exit_on_fail and return_code != 0:
- print("Command failed. Exiting.")
- sys.exit(1)
- return command_stdout, command_stderr, return_code
-
-
-def copy_directory(src_path, dst_path, verbose_output=True, match_func=lambda path: True):
- """Copies directory in 'src_path' to 'dst_path' maintaining the directory
- structure. https://docs.python.org/3.5/library/shutil.html#shutil.copytree can't
- be used in this case because it expects the destination directory should not
- exist, however we do call copy_directory() to copy files to same destination directory.
-
- Args:
- src_path (string): Path of source directory that need to be copied.
- dst_path (string): Path where directory should be copied.
- verbose_output (bool): True to print every copy or skipped file.
- match_func (str -> bool) : Criteria function determining if a file is copied.
- """
- if not os.path.exists(dst_path):
- os.makedirs(dst_path)
- for item in os.listdir(src_path):
- src_item = os.path.join(src_path, item)
- dst_item = os.path.join(dst_path, item)
- if os.path.isdir(src_item):
- copy_directory(src_item, dst_item, verbose_output, match_func)
- else:
- try:
- if match_func(src_item):
- if verbose_output:
- print("> copy {0} => {1}".format(src_item, dst_item))
- try:
- shutil.copy2(src_item, dst_item)
- except PermissionError as pe_error:
- print('Ignoring PermissionError: {0}'.format(pe_error))
- else:
- if verbose_output:
- print("> skipping {0}".format(src_item))
- except UnicodeEncodeError:
- if verbose_output:
- print("> Got UnicodeEncodeError")
-
-
-def copy_files(src_path, dst_path, file_names):
- """Copy files from 'file_names' list from 'src_path' to 'dst_path'.
- It retains the original directory structure of src_path.
-
- Args:
- src_path (string): Source directory from where files are copied.
- dst_path (string): Destination directory where files to be copied.
- file_names ([string]): List of full path file names to be copied.
- """
-
- print('### Copying below files from {0} to {1}:'.format(src_path, dst_path))
- print('')
- print(os.linesep.join(file_names))
- for f in file_names:
- # Create same structure in dst so we don't clobber same files names present in different directories
- dst_path_of_file = f.replace(src_path, dst_path)
-
- dst_directory = path.dirname(dst_path_of_file)
- if not os.path.exists(dst_directory):
- os.makedirs(dst_directory)
- try:
- shutil.copy2(f, dst_path_of_file)
- except PermissionError as pe_error:
- print('Ignoring PermissionError: {0}'.format(pe_error))
-
-
def partition_files(src_directory, dst_directory, max_size, exclude_directories=[],
exclude_files=native_binaries_to_ignore):
""" Copy bucketized files based on size to destination folder.
@@ -434,7 +327,7 @@ def partition_files(src_directory, dst_directory, max_size, exclude_directories=
index = 0
for p_index in partitions:
file_names = [curr_file[0] for curr_file in partitions[p_index]]
- curr_dst_path = path.join(dst_directory, str(index), "binaries")
+ curr_dst_path = os.path.join(dst_directory, str(index), "binaries")
copy_files(src_directory, curr_dst_path, file_names)
index += 1
@@ -446,7 +339,7 @@ def setup_microbenchmark(workitem_directory, arch):
workitem_directory (string): Path to work
arch (string): Architecture for which dotnet will be installed
"""
- performance_directory = path.join(workitem_directory, "performance")
+ performance_directory = os.path.join(workitem_directory, "performance")
run_command(
["git", "clone", "--quiet", "--depth", "1", "https://github.com/dotnet/performance", performance_directory])
@@ -455,7 +348,7 @@ def setup_microbenchmark(workitem_directory, arch):
dotnet_directory = os.path.join(performance_directory, "tools", "dotnet", arch)
dotnet_install_script = os.path.join(performance_directory, "scripts", "dotnet.py")
- if not isfile(dotnet_install_script):
+ if not os.path.isfile(dotnet_install_script):
print("Missing " + dotnet_install_script)
return
@@ -476,18 +369,6 @@ def get_python_name():
return ["python3"]
-def set_pipeline_variable(name, value):
- """ This method sets pipeline variable.
-
- Args:
- name (string): Name of the variable.
- value (string): Value of the variable.
- """
- define_variable_format = "##vso[task.setvariable variable={0}]{1}"
- print("{0} -> {1}".format(name, value)) # logging
- print(define_variable_format.format(name, value)) # set variable
-
-
def main(main_args):
""" Main entrypoint
@@ -498,9 +379,9 @@ def main(main_args):
source_directory = coreclr_args.source_directory
# CorrelationPayload directories
- correlation_payload_directory = path.join(coreclr_args.source_directory, "payload")
- superpmi_src_directory = path.join(source_directory, 'src', 'coreclr', 'scripts')
- superpmi_dst_directory = path.join(correlation_payload_directory, "superpmi")
+ correlation_payload_directory = os.path.join(coreclr_args.source_directory, "payload")
+ superpmi_src_directory = os.path.join(source_directory, 'src', 'coreclr', 'scripts')
+ superpmi_dst_directory = os.path.join(correlation_payload_directory, "superpmi")
arch = coreclr_args.arch
helix_source_prefix = "official"
creator = ""
@@ -546,7 +427,7 @@ def make_readable(folder_name):
print("Inside make_readable")
run_command(["ls", "-l", folder_name])
- for file_path, dirs, files in walk(folder_name, topdown=True):
+ for file_path, dirs, files in os.walk(folder_name, topdown=True):
for d in dirs:
os.chmod(os.path.join(file_path, d),
# read+write+execute for owner
@@ -570,7 +451,7 @@ def make_readable(folder_name):
copy_directory(coreclr_args.input_directory, superpmi_dst_directory, match_func=acceptable_copy)
# Workitem directories
- workitem_directory = path.join(source_directory, "workitem")
+ workitem_directory = os.path.join(source_directory, "workitem")
input_artifacts = ""
if coreclr_args.collection_name == "benchmarks":
@@ -581,21 +462,21 @@ def make_readable(folder_name):
# Clone and build jitutils
try:
- with tempfile.TemporaryDirectory() as jitutils_directory:
+ with TempDir() as jitutils_directory:
run_command(
["git", "clone", "--quiet", "--depth", "1", "https://github.com/dotnet/jitutils", jitutils_directory])
# Make sure ".dotnet" directory exists, by running the script at least once
dotnet_script_name = "dotnet.cmd" if is_windows else "dotnet.sh"
- dotnet_script_path = path.join(source_directory, dotnet_script_name)
+ dotnet_script_path = os.path.join(source_directory, dotnet_script_name)
run_command([dotnet_script_path, "--info"], jitutils_directory)
- # Set dotnet path to run bootstrap
- os.environ["PATH"] = path.join(source_directory, ".dotnet") + os.pathsep + os.environ["PATH"]
- bootstrap_file = "bootstrap.cmd" if is_windows else "bootstrap.sh"
- run_command([path.join(jitutils_directory, bootstrap_file)], jitutils_directory)
+ # Set dotnet path to run build
+ os.environ["PATH"] = os.path.join(source_directory, ".dotnet") + os.pathsep + os.environ["PATH"]
+ build_file = "build.cmd" if is_windows else "build.sh"
+ run_command([os.path.join(jitutils_directory, build_file), "-p"], jitutils_directory)
- copy_files(path.join(jitutils_directory, "bin"), superpmi_dst_directory, [path.join(jitutils_directory, "bin", "pmi.dll")])
+ copy_files(os.path.join(jitutils_directory, "bin"), superpmi_dst_directory, [os.path.join(jitutils_directory, "bin", "pmi.dll")])
except PermissionError as pe_error:
# Details: https://bugs.python.org/issue26660
print('Ignoring PermissionError: {0}'.format(pe_error))
@@ -606,14 +487,14 @@ def make_readable(folder_name):
# # Copy ".dotnet" to correlation_payload_directory for crossgen2 job; it is needed to invoke crossgen2.dll
# if coreclr_args.collection_type == "crossgen2":
- # dotnet_src_directory = path.join(source_directory, ".dotnet")
- # dotnet_dst_directory = path.join(correlation_payload_directory, ".dotnet")
+ # dotnet_src_directory = os.path.join(source_directory, ".dotnet")
+ # dotnet_dst_directory = os.path.join(correlation_payload_directory, ".dotnet")
# print('Copying {} -> {}'.format(dotnet_src_directory, dotnet_dst_directory))
# copy_directory(dotnet_src_directory, dotnet_dst_directory, verbose_output=False)
# payload
- pmiassemblies_directory = path.join(workitem_directory, "pmiAssembliesDirectory")
- input_artifacts = path.join(pmiassemblies_directory, coreclr_args.collection_name)
+ pmiassemblies_directory = os.path.join(workitem_directory, "pmiAssembliesDirectory")
+ input_artifacts = os.path.join(pmiassemblies_directory, coreclr_args.collection_name)
exclude_directory = ['Core_Root'] if coreclr_args.collection_name == "coreclr_tests" else []
exclude_files = native_binaries_to_ignore
if coreclr_args.collection_type == "crossgen2":
@@ -625,7 +506,7 @@ def make_readable(folder_name):
# libraries_tests artifacts contains files from core_root folder. Exclude them.
core_root_dir = coreclr_args.core_root_directory
exclude_files += [item for item in os.listdir(core_root_dir)
- if isfile(join(core_root_dir, item)) and (item.endswith(".dll") or item.endswith(".exe"))]
+ if os.path.isfile(os.path.join(core_root_dir, item)) and (item.endswith(".dll") or item.endswith(".exe"))]
partition_files(coreclr_args.input_directory, input_artifacts, coreclr_args.max_size, exclude_directory,
exclude_files)
diff --git a/src/coreclr/scripts/superpmi-replay.py b/src/coreclr/scripts/superpmi_replay.py
similarity index 78%
rename from src/coreclr/scripts/superpmi-replay.py
rename to src/coreclr/scripts/superpmi_replay.py
index 158c50162340c..a00b80753b2a9 100644
--- a/src/coreclr/scripts/superpmi-replay.py
+++ b/src/coreclr/scripts/superpmi_replay.py
@@ -3,22 +3,19 @@
# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the MIT license.
#
-##
-# Title : superpmi_setup.py
+# Title : superpmi_replay.py
#
# Notes:
#
-# Script to run "superpmi replay" for various collections under various COMPlus_JitStressRegs value.
+# Script to run "superpmi replay" for various collections under various COMPlus_JitStressRegs values.
+#
################################################################################
################################################################################
-
import argparse
-from os import path
import os
-from os import listdir
from coreclr_arguments import *
-from superpmi_setup import run_command
+from azdo_pipelines_util import run_command
parser = argparse.ArgumentParser(description="description")
@@ -86,40 +83,47 @@ def main(main_args):
python_path = sys.executable
cwd = os.path.dirname(os.path.realpath(__file__))
coreclr_args = setup_args(main_args)
- spmi_location = path.join(cwd, "artifacts", "spmi")
+ spmi_location = os.path.join(cwd, "artifacts", "spmi")
log_directory = coreclr_args.log_directory
platform_name = coreclr_args.platform
os_name = "win" if platform_name.lower() == "windows" else "unix"
arch_name = coreclr_args.arch
host_arch_name = "x64" if arch_name.endswith("64") else "x86"
os_name = "universal" if arch_name.startswith("arm") else os_name
- jit_path = path.join(coreclr_args.jit_directory, 'clrjit_{}_{}_{}.dll'.format(os_name, arch_name, host_arch_name))
+ jit_path = os.path.join(coreclr_args.jit_directory, 'clrjit_{}_{}_{}.dll'.format(os_name, arch_name, host_arch_name))
print("Running superpmi.py download")
- run_command([python_path, path.join(cwd, "superpmi.py"), "download", "--no_progress", "-target_os", platform_name,
+ run_command([python_path, os.path.join(cwd, "superpmi.py"), "download", "--no_progress", "-target_os", platform_name,
"-target_arch", arch_name, "-core_root", cwd, "-spmi_location", spmi_location], _exit_on_fail=True)
failed_runs = []
for jit_flag in jit_flags:
- log_file = path.join(log_directory, 'superpmi_{}.log'.format(jit_flag.replace("=", "_")))
+ log_file = os.path.join(log_directory, 'superpmi_{}.log'.format(jit_flag.replace("=", "_")))
print("Running superpmi.py replay for {}".format(jit_flag))
_, _, return_code = run_command([
- python_path, path.join(cwd, "superpmi.py"), "replay", "-core_root", cwd,
- "-jitoption", jit_flag, "-jitoption", "TieredCompilation=0",
- "-target_os", platform_name, "-target_arch", arch_name,
+ python_path,
+ os.path.join(cwd, "superpmi.py"),
+ "replay",
+ "-core_root", cwd,
+ "-jitoption", jit_flag,
+ "-jitoption", "TieredCompilation=0",
+ "-target_os", platform_name,
+ "-target_arch", arch_name,
"-arch", host_arch_name,
- "-jit_path", jit_path, "-spmi_location", spmi_location,
- "-log_level", "debug", "-log_file", log_file])
+ "-jit_path", jit_path,
+ "-spmi_location", spmi_location,
+ "-log_level", "debug",
+ "-log_file", log_file])
if return_code != 0:
failed_runs.append("Failure in {}".format(log_file))
# Consolidate all superpmi_*.logs in superpmi_platform_architecture.log
- final_log_name = path.join(log_directory, "superpmi_{}_{}.log".format(platform_name, arch_name))
+ final_log_name = os.path.join(log_directory, "superpmi_{}_{}.log".format(platform_name, arch_name))
print("Consolidating final {}".format(final_log_name))
with open(final_log_name, "a") as final_superpmi_log:
- for superpmi_log in listdir(log_directory):
+ for superpmi_log in os.listdir(log_directory):
if not superpmi_log.startswith("superpmi_Jit") or not superpmi_log.endswith(".log"):
continue
@@ -127,7 +131,7 @@ def main(main_args):
final_superpmi_log.write("======================================================={}".format(os.linesep))
final_superpmi_log.write("Contents from {}{}".format(superpmi_log, os.linesep))
final_superpmi_log.write("======================================================={}".format(os.linesep))
- with open(path.join(log_directory, superpmi_log), "r") as current_superpmi_log:
+ with open(os.path.join(log_directory, superpmi_log), "r") as current_superpmi_log:
contents = current_superpmi_log.read()
final_superpmi_log.write(contents)
diff --git a/src/coreclr/scripts/superpmi_replay_setup.py b/src/coreclr/scripts/superpmi_replay_setup.py
index c6c6fcb507f89..73c89eb333556 100644
--- a/src/coreclr/scripts/superpmi_replay_setup.py
+++ b/src/coreclr/scripts/superpmi_replay_setup.py
@@ -3,27 +3,21 @@
# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the MIT license.
#
-##
# Title : superpmi_replay_setup.py
#
# Notes:
#
# Script to setup directory structure required to perform SuperPMI replay in CI.
-# It creates `correlation_payload_directory` that contains clrjit*_x64.dll and clrjit*_x86.dll
+# It creates `correlation_payload_directory` that contains clrjit*_x64.dll and clrjit*_x86.dll
+#
################################################################################
################################################################################
import argparse
-from os import path, walk
import os
-import shutil
-import stat
-import subprocess
-import tempfile
-from os.path import isfile, join
from coreclr_arguments import *
-from superpmi_setup import copy_directory, copy_files, set_pipeline_variable, run_command
+from azdo_pipelines_util import copy_directory, copy_files, set_pipeline_variable
parser = argparse.ArgumentParser(description="description")
@@ -63,38 +57,10 @@ def setup_args(args):
return coreclr_args
-def partition_mch(mch_directory, dst_directory):
- from os import listdir
-
- print("Inside partition_mch")
- mch_zip_files = []
- for file_path, dirs, files in walk(mch_directory, topdown=True):
- for name in files:
- curr_file_path = path.join(file_path, name)
-
- if not isfile(curr_file_path):
- continue
- if not name.endswith(".mch.zip"):
- continue
-
- mch_zip_files.append(curr_file_path)
-
- index = 1
- for mch_file in mch_zip_files:
- print("Processing {}".format(mch_file))
- file_names = []
- file_names += [mch_file]
- file_names += [mch_file.replace(".mch.zip", ".mch.mct.zip")]
- curr_dst_path = path.join(dst_directory, "partitions", str(index))
- copy_files(mch_directory, curr_dst_path, file_names)
- index += 1
-
-
def match_correlation_files(full_path):
file_name = os.path.basename(full_path)
- if file_name.startswith("clrjit_") and file_name.endswith(".dll") and file_name.find(
- "osx") == -1:
+ if file_name.startswith("clrjit_") and file_name.endswith(".dll") and file_name.find("osx") == -1:
return True
if file_name == "superpmi.exe" or file_name == "mcs.exe":
@@ -116,13 +82,11 @@ def main(main_args):
product_directory = coreclr_args.product_directory
# CorrelationPayload directories
- correlation_payload_directory = path.join(coreclr_args.source_directory, "payload")
- superpmi_src_directory = path.join(source_directory, 'src', 'coreclr', 'scripts')
+ correlation_payload_directory = os.path.join(source_directory, "payload")
+ superpmi_src_directory = os.path.join(source_directory, 'src', 'coreclr', 'scripts')
helix_source_prefix = "official"
creator = ""
- ci = True
- helix_queue = "Windows.10.Amd64.X86"
# Copy *.py to CorrelationPayload
print('Copying {} -> {}'.format(superpmi_src_directory, correlation_payload_directory))
@@ -130,7 +94,7 @@ def main(main_args):
match_func=lambda path: any(path.endswith(extension) for extension in [".py"]))
# Copy clrjit*_arch.dll binaries to CorrelationPayload
- print('Copying binaries {} -> {}'.format(arch, product_directory, correlation_payload_directory))
+ print('Copying binaries {} -> {}'.format(product_directory, correlation_payload_directory))
copy_directory(product_directory, correlation_payload_directory, match_func=match_correlation_files)
# Set variables
@@ -138,7 +102,6 @@ def main(main_args):
set_pipeline_variable("CorrelationPayloadDirectory", correlation_payload_directory)
set_pipeline_variable("Architecture", arch)
set_pipeline_variable("Creator", creator)
- set_pipeline_variable("Queue", helix_queue)
set_pipeline_variable("HelixSourcePrefix", helix_source_prefix)
diff --git a/src/coreclr/tools/Common/Compiler/Logging/CompilerGeneratedState.cs b/src/coreclr/tools/Common/Compiler/Logging/CompilerGeneratedState.cs
index 4a5f482d35048..c2d861e62b2f6 100644
--- a/src/coreclr/tools/Common/Compiler/Logging/CompilerGeneratedState.cs
+++ b/src/coreclr/tools/Common/Compiler/Logging/CompilerGeneratedState.cs
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/CompilerGeneratedState.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/CompilerGeneratedState.cs
index 9df15ab508906..34821288b76d9 100644
--- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/CompilerGeneratedState.cs
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/CompilerGeneratedState.cs
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Mono.Cecil;
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs
index 9417723276745..7977343d17d5a 100644
--- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs
index 701f3c0e56cde..364216788ba61 100644
--- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs
index 197e04c33e380..a8962fa2e3c1d 100644
--- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs
@@ -877,7 +877,7 @@ private void ParseInstanceMethodEntrypointsCustom(provider, default(TGenericContext), mdReader.MetadataReader, this, (int)curParser.Offset);
+ var decoder = new R2RSignatureDecoder(provider, default(TGenericContext), mdReader?.MetadataReader, this, (int)curParser.Offset);
TMethod customMethod = decoder.ParseMethod();
@@ -887,7 +887,6 @@ private void ParseInstanceMethodEntrypointsCustom
+ {
+ public JittedID(long methodID, long reJITID)
+ {
+ MethodID = methodID;
+ ReJITID = reJITID;
+ }
+
+ public readonly long MethodID;
+ public readonly long ReJITID;
+
+ public override int GetHashCode() => HashCode.Combine(MethodID, ReJITID);
+ public override bool Equals([NotNullWhen(true)] object obj) => obj is JittedID id ? Equals(id) : false;
+
+ public bool Equals(JittedID other)
+ {
+ if (other.MethodID != MethodID)
+ return false;
+ return other.ReJITID == ReJITID;
+ }
+ }
+
public MethodMemoryMap(
TraceProcess p,
TraceTypeSystemContext tsc,
TraceRuntimeDescToTypeSystemDesc idParser,
- int clrInstanceID)
+ int clrInstanceID,
+ Logger logger)
{
// Capture the addresses of jitted code
List infos = new List();
- Dictionary info = new Dictionary();
+ Dictionary info = new Dictionary();
foreach (var e in p.EventsInProcess.ByEventType())
{
if (e.ClrInstanceID != clrInstanceID)
@@ -47,13 +71,16 @@ public MethodMemoryMap(
if (method != null)
{
- infos.Add(new MemoryRegionInfo
+ JittedID jittedID = new JittedID(e.MethodID, 0);
+ if (!info.ContainsKey(jittedID))
{
- StartAddress = e.MethodStartAddress,
- EndAddress = e.MethodStartAddress + checked((uint)e.MethodSize),
- MethodID = e.MethodID,
- Method = method,
- });
+ info.Add(jittedID, new MemoryRegionInfo
+ {
+ StartAddress = e.MethodStartAddress,
+ EndAddress = e.MethodStartAddress + checked((uint)e.MethodSize),
+ Method = method,
+ });
+ }
}
}
@@ -67,7 +94,7 @@ public MethodMemoryMap(
MethodDesc method = null;
try
{
- method = idParser.ResolveMethodID(e.MethodID);
+ method = idParser.ResolveMethodID(e.MethodID, throwIfNotFound: false);
}
catch
{
@@ -75,17 +102,20 @@ public MethodMemoryMap(
if (method != null)
{
- infos.Add(new MemoryRegionInfo
+ JittedID jittedID = new JittedID(e.MethodID, e.ReJITID);
+ if (!info.ContainsKey(jittedID))
{
- StartAddress = e.MethodStartAddress,
- EndAddress = e.MethodStartAddress + checked((uint)e.MethodSize),
- MethodID = e.MethodID,
- Method = method,
- });
+ info.Add(jittedID, new MemoryRegionInfo
+ {
+ StartAddress = e.MethodStartAddress,
+ EndAddress = e.MethodStartAddress + checked((uint)e.MethodSize),
+ Method = method,
+ });
+ }
}
}
- var sigProvider = new R2RSignatureTypeProvider(tsc);
+ var sigProvider = new R2RSignatureTypeProviderForGlobalTables(tsc);
foreach (var module in p.LoadedModules)
{
if (module.FilePath == "")
@@ -120,18 +150,40 @@ public MethodMemoryMap(
}
}
}
- catch { }
+ catch
+ {
+ logger.PrintWarning($"Failed to load method entry points from R2R module {module.FilePath}");
+ }
}
- // Can have duplicate events, so pick first for each
- var byMethodID = infos.GroupBy(i => i.MethodID).ToDictionary(g => g.Key, g => g.First());
+ // Associate NativeToILMap with MethodLoad event found Memory Regions
foreach (MethodILToNativeMapTraceData e in p.EventsInProcess.ByEventType())
{
- if (byMethodID.TryGetValue(e.MethodID, out MemoryRegionInfo inf))
+ if (info.TryGetValue(new JittedID(e.MethodID, e.ReJITID), out MemoryRegionInfo inf))
inf.NativeToILMap = NativeToILMap.FromEvent(e);
}
- _infos = byMethodID.Values.OrderBy(i => i.StartAddress).ToArray();
+ // Sort the R2R data by StartAddress
+ MemoryRegionInfoStartAddressComparer startAddressComparer = new MemoryRegionInfoStartAddressComparer();
+ infos.Sort(startAddressComparer);
+
+ // For each method found via MethodLoad events, check to see if it exists in the infos array, and if it does not, build a list to add
+ List memoryRegionsToAdd = new List();
+ foreach (var methodLoadInfo in info.Values)
+ {
+ int searchResult = infos.BinarySearch(methodLoadInfo, startAddressComparer);
+ if (searchResult < 0)
+ {
+ memoryRegionsToAdd.Add(methodLoadInfo);
+ }
+ }
+
+ // Add the regions from the MethodLoad events, and keep the overall array sorted
+ infos.AddRange(memoryRegionsToAdd);
+ infos.Sort(startAddressComparer);
+
+ _infos = infos.ToArray();
+
_infoKeys = _infos.Select(i => i.StartAddress).ToArray();
#if DEBUG
@@ -164,13 +216,17 @@ public MemoryRegionInfo GetInfo(ulong ip)
}
public MethodDesc GetMethod(ulong ip) => GetInfo(ip)?.Method;
+
+ private class MemoryRegionInfoStartAddressComparer : IComparer
+ {
+ int IComparer.Compare(MemoryRegionInfo x, MemoryRegionInfo y) => x.StartAddress.CompareTo(y.StartAddress);
+ }
}
public class MemoryRegionInfo
{
public ulong StartAddress { get; set; }
public ulong EndAddress { get; set; }
- public long MethodID { get; set; }
public MethodDesc Method { get; set; }
public NativeToILMap NativeToILMap { get; set; }
}
diff --git a/src/coreclr/tools/dotnet-pgo/ModuleLoadLogger.cs b/src/coreclr/tools/dotnet-pgo/ModuleLoadLogger.cs
index fb9afffb517ce..0271bb930b877 100644
--- a/src/coreclr/tools/dotnet-pgo/ModuleLoadLogger.cs
+++ b/src/coreclr/tools/dotnet-pgo/ModuleLoadLogger.cs
@@ -18,13 +18,28 @@ public ModuleLoadLogger(Logger logger)
Logger _logger;
+ [ThreadStatic]
+ private static int s_loadFailuresAreErrors = 0;
+
+ public class LoadFailuresAsErrors : IDisposable
+ {
+ public LoadFailuresAsErrors()
+ {
+ s_loadFailuresAreErrors++;
+ }
+ public void Dispose()
+ {
+ s_loadFailuresAreErrors--;
+ }
+ }
+
public void LogModuleLoadFailure(string simpleName, string filePath)
{
if (_simpleNamesReported.Add(simpleName))
{
string str = $"Failed to load assembly '{simpleName}' from '{filePath}'";
- if (String.Compare("System.Private.CoreLib", simpleName, StringComparison.OrdinalIgnoreCase) == 0)
+ if (s_loadFailuresAreErrors != 0 || String.Compare("System.Private.CoreLib", simpleName, StringComparison.OrdinalIgnoreCase) == 0)
{
_logger.PrintError(str);
}
@@ -41,7 +56,7 @@ public void LogModuleLoadFailure(string simpleName)
{
string str = $"Failed to load assembly '{simpleName}'";
- if (String.Compare("System.Private.CoreLib", simpleName, StringComparison.OrdinalIgnoreCase) == 0)
+ if (s_loadFailuresAreErrors != 0 || String.Compare("System.Private.CoreLib", simpleName, StringComparison.OrdinalIgnoreCase) == 0)
{
_logger.PrintError(str);
}
diff --git a/src/coreclr/tools/dotnet-pgo/Program.cs b/src/coreclr/tools/dotnet-pgo/Program.cs
index 77113377c478d..4636a4184a509 100644
--- a/src/coreclr/tools/dotnet-pgo/Program.cs
+++ b/src/coreclr/tools/dotnet-pgo/Program.cs
@@ -948,9 +948,11 @@ static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions)
return -5;
}
- if (!p.EventsInProcess.ByEventType().Any())
+ if (!p.EventsInProcess.ByEventType().Any() &&
+ !p.EventsInProcess.ByEventType().Any() &&
+ !p.EventsInProcess.ByEventType< SampledProfileTraceData>().Any())
{
- PrintError($"No managed jit starting data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
+ PrintError($"No data in trace for process\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
return -5;
}
@@ -1014,7 +1016,9 @@ static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions)
filePathError = true;
}
else
- tsc.GetModuleFromPath(fileReference.FullName);
+ {
+ tsc.GetModuleFromPath(fileReference.FullName, throwIfNotLoadable: false);
+ }
}
catch (Internal.TypeSystem.TypeSystemException.BadImageFormatException)
{
@@ -1034,7 +1038,63 @@ static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions)
TraceRuntimeDescToTypeSystemDesc idParser = new TraceRuntimeDescToTypeSystemDesc(p, tsc, clrInstanceId.Value);
- SortedDictionary methodsToAttemptToPrepare = new SortedDictionary();
+ int mismatchErrors = 0;
+ foreach (var e in p.EventsInProcess.ByEventType())
+ {
+ ModuleDesc loadedModule = idParser.ResolveModuleID(e.ModuleID, false);
+ if (loadedModule == null)
+ {
+ PrintWarning($"Unable to find loaded module {e.ModuleILFileName} to verify match");
+ continue;
+ }
+
+ EcmaModule ecmaModule = loadedModule as EcmaModule;
+ if (ecmaModule == null)
+ {
+ continue;
+ }
+
+ bool matched = false;
+ bool mismatch = false;
+ foreach (var debugEntry in ecmaModule.PEReader.ReadDebugDirectory())
+ {
+ if (debugEntry.Type == DebugDirectoryEntryType.CodeView)
+ {
+ var codeViewData = ecmaModule.PEReader.ReadCodeViewDebugDirectoryData(debugEntry);
+ if (codeViewData.Path.EndsWith("ni.pdb"))
+ continue;
+ if (codeViewData.Guid != e.ManagedPdbSignature)
+ {
+ PrintError($"Dll mismatch between assembly located at \"{e.ModuleILPath}\" during trace collection and module \"{tsc.PEReaderToFilePath(ecmaModule.PEReader)}\"");
+ mismatchErrors++;
+ mismatch = true;
+ continue;
+ }
+ else
+ {
+ matched = true;
+ }
+ }
+ }
+
+ if (!matched && !mismatch)
+ {
+ PrintMessage($"Unable to validate match between assembly located at \"{e.ModuleILPath}\" during trace collection and module \"{tsc.PEReaderToFilePath(ecmaModule.PEReader)}\"");
+ }
+
+ // TODO find some way to match on MVID as only some dlls have managed pdbs, and this won't find issues with embedded pdbs
+ }
+
+ if (mismatchErrors != 0)
+ {
+ PrintError($"{mismatchErrors} mismatch error(s) found");
+ return -1;
+ }
+
+ // Now that the modules are validated run Init to prepare for the rest of execution
+ idParser.Init();
+
+ SortedDictionary methodsToAttemptToPrepare = new SortedDictionary();
if (commandLineOptions.ProcessR2REvents)
{
@@ -1133,7 +1193,8 @@ MethodMemoryMap GetMethodMemMap()
p,
tsc,
idParser,
- clrInstanceId.Value);
+ clrInstanceId.Value,
+ s_logger);
}
return methodMemMap;
@@ -1155,6 +1216,9 @@ MethodMemoryMap GetMethodMemMap()
MethodMemoryMap mmap = GetMethodMemMap();
foreach (var e in p.EventsInProcess.ByEventType())
{
+ if ((e.TimeStampRelativeMSec < commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec > commandLineOptions.ExcludeEventsAfter))
+ continue;
+
var callstack = e.CallStack();
if (callstack == null)
continue;
@@ -1191,7 +1255,7 @@ MethodMemoryMap GetMethodMemMap()
if (!methodsListedToPrepare.Contains(nextMethod))
{
methodsListedToPrepare.Add(nextMethod);
- methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, nextMethod, "SampleMethodCaller"));
+ methodsToAttemptToPrepare.Add(0x100000000 + (int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, nextMethod, "SampleMethodCaller"));
}
if (!callGraph.TryGetValue(nextMethod, out var innerDictionary))
diff --git a/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs b/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
index a640425f209b4..3f68a63e271b3 100644
--- a/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
+++ b/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
@@ -1,7 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Immutable;
+using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ILCompiler.Reflection.ReadyToRun;
@@ -109,7 +111,7 @@ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMethodDef(MetadataReader reader, MethodDefinitionHandle handle, TypeDesc owningTypeOverride)
+ protected MethodDesc GetMethodFromMethodDef(MetadataReader reader, MethodDefinitionHandle handle, TypeDesc owningTypeOverride)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
var method = (MethodDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
@@ -119,11 +121,19 @@ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMethodDef(MetadataReader reader, MethodDefinitionHandle handle, TypeDesc owningTypeOverride)
+ {
+ return GetMethodFromMethodDef(reader, handle, owningTypeOverride);
+ }
+
MethodDesc IR2RSignatureTypeProvider.GetMethodWithFlags(ReadyToRunMethodSigFlags flags, MethodDesc method)
{
return method;
@@ -237,4 +247,27 @@ TypeDesc ISignatureTypeProvider.GetTypeFromSpec
return (TypeDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
}
}
+
+ class R2RSignatureTypeProviderForGlobalTables : R2RSignatureTypeProvider, IR2RSignatureTypeProvider
+ {
+ public R2RSignatureTypeProviderForGlobalTables(TraceTypeSystemContext tsc) : base(tsc)
+ {
+ }
+
+ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMethodDef(MetadataReader reader, MethodDefinitionHandle handle, TypeDesc owningTypeOverride)
+ {
+ if (owningTypeOverride != null)
+ {
+ reader = ((EcmaModule)((MetadataType)owningTypeOverride.GetTypeDefinition()).Module).MetadataReader;
+ }
+ Debug.Assert(reader != null);
+ return GetMethodFromMethodDef(reader, handle, owningTypeOverride);
+ }
+
+ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMemberRef(MetadataReader reader, MemberReferenceHandle handle, TypeDesc owningTypeOverride)
+ {
+ // Global signature cannot have MemberRef entries in them as such things aren't uniquely identifiable
+ throw new NotSupportedException();
+ }
+ }
}
diff --git a/src/coreclr/tools/dotnet-pgo/TraceRuntimeDescToTypeSystemDesc.cs b/src/coreclr/tools/dotnet-pgo/TraceRuntimeDescToTypeSystemDesc.cs
index cb1816a26e073..90e4e96c37310 100644
--- a/src/coreclr/tools/dotnet-pgo/TraceRuntimeDescToTypeSystemDesc.cs
+++ b/src/coreclr/tools/dotnet-pgo/TraceRuntimeDescToTypeSystemDesc.cs
@@ -93,15 +93,15 @@ public override string ToString()
class ModuleDescInfo
{
- public ModuleDescInfo(long id, TraceManagedModule traceManagedModule)
+ public ModuleDescInfo(long id, string assemblyName)
{
ID = id;
- TraceManagedModule = traceManagedModule;
+ AssemblyName = assemblyName;
}
public readonly long ID;
public ModuleDesc Module;
- public readonly TraceManagedModule TraceManagedModule;
+ public readonly string AssemblyName;
}
private readonly Dictionary _methods = new Dictionary();
@@ -222,9 +222,11 @@ public TraceRuntimeDescToTypeSystemDesc(TraceProcess traceProcess, TypeSystemCon
}
Dictionary assemblyToCLRInstanceIDMap = new Dictionary();
+ Dictionary assemblyToFullyQualifiedAssemblyName = new Dictionary();
foreach (var assemblyLoadTrace in _traceProcess.EventsInProcess.ByEventType())
{
assemblyToCLRInstanceIDMap[assemblyLoadTrace.AssemblyID] = assemblyLoadTrace.ClrInstanceID;
+ assemblyToFullyQualifiedAssemblyName[assemblyLoadTrace.AssemblyID] = assemblyLoadTrace.FullyQualifiedAssemblyName;
}
foreach (var moduleFile in _traceProcess.LoadedModules)
@@ -240,20 +242,15 @@ public TraceRuntimeDescToTypeSystemDesc(TraceProcess traceProcess, TypeSystemCon
if (clrInstanceIDModule != _clrInstanceID)
continue;
- if (managedModule.ModuleFile != null)
- {
- ModuleDescInfo currentInfo;
- if (_modules.TryGetValue(managedModule.ModuleID, out currentInfo))
- {
- continue;
- }
- currentInfo = new ModuleDescInfo(managedModule.ModuleID, managedModule);
- _modules.Add(managedModule.ModuleID, currentInfo);
- }
+ var currentInfo = new ModuleDescInfo(managedModule.ModuleID, assemblyToFullyQualifiedAssemblyName[managedModule.AssemblyID]);
+ _modules.Add(managedModule.ModuleID, currentInfo);
}
}
+ }
-
+ // Call before any api other than ResolveModuleID will work
+ public void Init()
+ {
// Fill in all the types
foreach (var entry in _types)
{
@@ -271,14 +268,7 @@ public ModuleDesc ResolveModuleID(long handle, bool throwIfNotFound = true)
if (minfo.Module != null)
return minfo.Module;
- string simpleName = minfo.TraceManagedModule.Name;
-
- if (!File.Exists(minfo.TraceManagedModule.FilePath) && minfo.TraceManagedModule.FilePath.EndsWith(".il.dll") && simpleName.EndsWith(".il"))
- {
- simpleName = simpleName.Substring(0, simpleName.Length - 3);
- }
-
- minfo.Module = _context.ResolveAssembly(new AssemblyName(simpleName), throwIfNotFound);
+ minfo.Module = _context.ResolveAssembly(new AssemblyName(minfo.AssemblyName), throwIfNotFound);
return minfo.Module;
}
else
diff --git a/src/coreclr/tools/dotnet-pgo/TraceTypeSystemContext.cs b/src/coreclr/tools/dotnet-pgo/TraceTypeSystemContext.cs
index 3f0155fc5b76c..09e2f52ea053a 100644
--- a/src/coreclr/tools/dotnet-pgo/TraceTypeSystemContext.cs
+++ b/src/coreclr/tools/dotnet-pgo/TraceTypeSystemContext.cs
@@ -16,6 +16,7 @@
using Microsoft.Diagnostics.Tracing.Parsers.Clr;
using System.Reflection.Metadata;
using ILCompiler.Reflection.ReadyToRun;
+using System.Runtime.CompilerServices;
namespace Microsoft.Diagnostics.Tools.Pgo
{
@@ -181,9 +182,9 @@ public ModuleDesc GetModuleForSimpleName(string simpleName, bool throwIfNotFound
}
}
- public EcmaModule GetModuleFromPath(string filePath)
+ public EcmaModule GetModuleFromPath(string filePath, bool throwIfNotLoadable = true)
{
- return GetOrAddModuleFromPath(filePath, null, true);
+ return GetOrAddModuleFromPath(filePath, null, true, throwIfNotLoadable: throwIfNotLoadable);
}
public EcmaModule GetMetadataOnlyModuleFromPath(string filePath)
@@ -196,7 +197,7 @@ public EcmaModule GetMetadataOnlyModuleFromMemory(string filePath, byte[] module
return GetOrAddModuleFromPath(filePath, moduleData, false);
}
- private EcmaModule GetOrAddModuleFromPath(string filePath, byte[] moduleData, bool useForBinding)
+ private EcmaModule GetOrAddModuleFromPath(string filePath, byte[] moduleData, bool useForBinding, bool throwIfNotLoadable = true)
{
// This method is not expected to be called frequently. Linear search is acceptable.
foreach (var entry in ModuleHashtable.Enumerator.Get(_moduleHashtable))
@@ -208,10 +209,13 @@ private EcmaModule GetOrAddModuleFromPath(string filePath, byte[] moduleData, bo
bool succeeded = false;
try
{
- EcmaModule returnValue = AddModule(filePath, null, moduleData, useForBinding);
- _moduleLoadLogger.LogModuleLoadSuccess(returnValue.Assembly.GetName().Name, filePath);
- succeeded = true;
- return returnValue;
+ EcmaModule returnValue = AddModule(filePath, null, moduleData, useForBinding, throwIfNotLoadable: throwIfNotLoadable);
+ if (returnValue != null)
+ {
+ _moduleLoadLogger.LogModuleLoadSuccess(returnValue.Assembly.GetName().Name, filePath);
+ succeeded = true;
+ return returnValue;
+ }
}
finally
{
@@ -220,6 +224,20 @@ private EcmaModule GetOrAddModuleFromPath(string filePath, byte[] moduleData, bo
_moduleLoadLogger.LogModuleLoadFailure(Path.GetFileNameWithoutExtension(filePath), filePath);
}
}
+ return null;
+ }
+
+ private static ConditionalWeakTable s_peReaderToPath = new ConditionalWeakTable();
+
+ // Get the file path used to load a PEReader or "Memory" if it wasn't loaded from a file
+ public string PEReaderToFilePath(PEReader reader)
+ {
+ if (!s_peReaderToPath.TryGetValue(reader, out string filepath))
+ {
+ filepath = "Memory";
+ }
+
+ return filepath;
}
public static unsafe PEReader OpenPEFile(string filePath, byte[] moduleBytes, out MemoryMappedViewAccessor mappedViewAccessor)
@@ -249,6 +267,7 @@ public static unsafe PEReader OpenPEFile(string filePath, byte[] moduleBytes, ou
var safeBuffer = accessor.SafeMemoryMappedViewHandle;
var peReader = new PEReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength);
+ s_peReaderToPath.Add(peReader, filePath);
// MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough.
@@ -268,13 +287,17 @@ public static unsafe PEReader OpenPEFile(string filePath, byte[] moduleBytes, ou
}
}
- private EcmaModule AddModule(string filePath, string expectedSimpleName, byte[] moduleDataBytes, bool useForBinding)
+ private EcmaModule AddModule(string filePath, string expectedSimpleName, byte[] moduleDataBytes, bool useForBinding, bool throwIfNotLoadable = true)
{
MemoryMappedViewAccessor mappedViewAccessor = null;
PdbSymbolReader pdbReader = null;
try
{
PEReader peReader = OpenPEFile(filePath, moduleDataBytes, out mappedViewAccessor);
+ if ((!peReader.HasMetadata) && !throwIfNotLoadable)
+ {
+ return null;
+ }
pdbReader = OpenAssociatedSymbolFile(filePath, peReader);
EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader);
@@ -316,6 +339,10 @@ private EcmaModule AddModule(string filePath, string expectedSimpleName, byte[]
return module;
}
+ catch when (!throwIfNotLoadable)
+ {
+ return null;
+ }
finally
{
if (mappedViewAccessor != null)
@@ -375,12 +402,14 @@ public MetadataStringDecoder GetMetadataStringDecoder()
IAssemblyMetadata IAssemblyResolver.FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile)
{
+ using var triggerErrors = new ModuleLoadLogger.LoadFailuresAsErrors();
EcmaAssembly ecmaAssembly = (EcmaAssembly)this.GetModuleForSimpleName(metadataReader.GetString(metadataReader.GetAssemblyReference(assemblyReferenceHandle).Name), false);
return new StandaloneAssemblyMetadata(ecmaAssembly.PEReader);
}
IAssemblyMetadata IAssemblyResolver.FindAssembly(string simpleName, string parentFile)
{
+ using var triggerErrors = new ModuleLoadLogger.LoadFailuresAsErrors();
EcmaAssembly ecmaAssembly = (EcmaAssembly)this.GetModuleForSimpleName(simpleName, false);
return new StandaloneAssemblyMetadata(ecmaAssembly.PEReader);
}
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index da3a36468c06c..a1b164a0af65d 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -106,7 +106,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
nativeimage.cpp
object.cpp
onstackreplacement.cpp
- pefile.cpp
+ peassembly.cpp
peimage.cpp
perfmap.cpp
perfinfo.cpp
@@ -207,8 +207,8 @@ set(VM_HEADERS_DAC_AND_WKS_COMMON
object.h
object.inl
onstackreplacement.h
- pefile.h
- pefile.inl
+ peassembly.h
+ peassembly.inl
peimage.h
peimage.inl
peimagelayout.h
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index d76db29301529..61c4c08e24925 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -1041,7 +1041,6 @@ void SystemDomain::Attach()
// Create the one and only app domain
AppDomain::Create();
- AppDomain::GetCurrentDomain()->CreateBinderContext();
// Each domain gets its own ReJitManager, and ReJitManager has its own static
// initialization to run
@@ -1174,7 +1173,7 @@ void SystemDomain::Init()
if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
g_fAllowNativeImages = false;
- m_pSystemFile = NULL;
+ m_pSystemPEAssembly = NULL;
m_pSystemAssembly = NULL;
DWORD size = 0;
@@ -1320,12 +1319,11 @@ void SystemDomain::LoadBaseSystemClasses()
ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
- {
- m_pSystemFile = PEAssembly::OpenSystem();
- }
+ m_pSystemPEAssembly = PEAssembly::OpenSystem();
+
// Only partially load the system assembly. Other parts of the code will want to access
// the globals in this function before finishing the load.
- m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
+ m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemPEAssembly, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
// Set up binder for CoreLib
CoreLibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
@@ -1839,6 +1837,8 @@ void AppDomain::Create()
pDomain->InitVSD();
pDomain->SetStage(AppDomain::STAGE_OPEN);
+ pDomain->CreateDefaultBinder();
+
pDomain.SuppressRelease();
m_pTheAppDomain = pDomain;
@@ -2251,7 +2251,7 @@ DispIDCache* AppDomain::SetupRefDispIDCache()
#endif // FEATURE_COMINTEROP
-FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
+FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEAssembly * pPEAssembly, DomainFile *pDomainFile)
{
CONTRACTL
{
@@ -2259,12 +2259,12 @@ FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainF
GC_TRIGGERS;
MODE_ANY;
PRECONDITION(pLock->HasLock());
- PRECONDITION(pLock->FindFileLock(pFile) == NULL);
+ PRECONDITION(pLock->FindFileLock(pPEAssembly) == NULL);
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;
- NewHolder result(new FileLoadLock(pLock, pFile, pDomainFile));
+ NewHolder result(new FileLoadLock(pLock, pPEAssembly, pDomainFile));
pLock->AddElement(result);
result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
@@ -2281,7 +2281,7 @@ FileLoadLock::~FileLoadLock()
MODE_ANY;
}
CONTRACTL_END;
- ((PEFile *) m_data)->Release();
+ ((PEAssembly *) m_data)->Release();
}
DomainFile *FileLoadLock::GetDomainFile()
@@ -2476,14 +2476,14 @@ UINT32 FileLoadLock::Release()
return count;
}
-FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
- : ListLockEntry(pLock, pFile, "File load lock"),
+FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEAssembly * pPEAssembly, DomainFile *pDomainFile)
+ : ListLockEntry(pLock, pPEAssembly, "File load lock"),
m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
m_pDomainFile(pDomainFile),
m_cachedHR(S_OK)
{
WRAPPER_NO_CONTRACT;
- pFile->AddRef();
+ pPEAssembly->AddRef();
}
void FileLoadLock::HolderLeave(FileLoadLock *pThis)
@@ -2531,7 +2531,7 @@ void AppDomain::LoadSystemAssemblies()
//
// Right now we have only one system assembly. We shouldn't need to add any more.
- LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
+ LoadAssembly(NULL, SystemDomain::System()->SystemPEAssembly(), FILE_ACTIVE);
}
FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
@@ -2546,7 +2546,7 @@ FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
LoadLockHolder lock(this);
- FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
+ FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly());
if (pLockEntry == NULL)
return pFile->GetLoadLevel();
@@ -2576,7 +2576,7 @@ BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
{
LoadLockHolder lock(this);
- pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
+ pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly());
if (pLock == NULL)
{
@@ -2613,7 +2613,7 @@ CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
LoadLockHolder lock(this);
- pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
+ pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly());
if (pLock != NULL
&& pLock->CanAcquire(level))
@@ -2699,7 +2699,7 @@ void AppDomain::LoadDomainFile(DomainFile *pFile,
// Load some more if appropriate
LoadLockHolder lock(this);
- FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
+ FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetPEAssembly());
if (pLockEntry == NULL)
{
_ASSERTE (!pFile->IsLoading());
@@ -2731,7 +2731,7 @@ FileLoadLevel AppDomain::GetThreadFileLoadLevel()
Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
- PEAssembly *pFile,
+ PEAssembly * pPEAssembly,
FileLoadLevel targetLevel)
{
CONTRACT(Assembly *)
@@ -2739,20 +2739,20 @@ Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
GC_TRIGGERS;
THROWS;
MODE_ANY;
- PRECONDITION(CheckPointer(pFile));
+ PRECONDITION(CheckPointer(pPEAssembly));
POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACT_END;
- DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
+ DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pPEAssembly, targetLevel);
PREFIX_ASSUME(pAssembly != NULL);
RETURN pAssembly->GetAssembly();
}
DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec,
- PEAssembly *pFile,
+ PEAssembly * pPEAssembly,
FileLoadLevel targetLevel)
{
STATIC_CONTRACT_THROWS;
@@ -2760,13 +2760,13 @@ DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec,
if (pSpec == nullptr)
{
// skip caching, since we don't have anything to base it on
- return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
+ return LoadDomainAssemblyInternal(pSpec, pPEAssembly, targetLevel);
}
DomainAssembly* pRetVal = NULL;
EX_TRY
{
- pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
+ pRetVal = LoadDomainAssemblyInternal(pSpec, pPEAssembly, targetLevel);
}
EX_HOOK
{
@@ -2775,7 +2775,7 @@ DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec,
{
// Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
AssemblyBinder* pCurrentBinder = pSpec->GetBinder();
- AssemblyBinder* pBinderFromPEAssembly = pFile->GetAssemblyBinder();
+ AssemblyBinder* pBinderFromPEAssembly = pPEAssembly->GetAssemblyBinder();
if (pCurrentBinder == NULL)
{
@@ -2811,7 +2811,7 @@ DomainAssembly* AppDomain::LoadDomainAssembly(AssemblySpec* pSpec,
DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
- PEAssembly *pFile,
+ PEAssembly * pPEAssembly,
FileLoadLevel targetLevel)
{
CONTRACT(DomainAssembly *)
@@ -2819,8 +2819,8 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
GC_TRIGGERS;
THROWS;
MODE_ANY;
- PRECONDITION(CheckPointer(pFile));
- PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
+ PRECONDITION(CheckPointer(pPEAssembly));
+ PRECONDITION(::GetAppDomain()==this);
POSTCONDITION(CheckPointer(RETVAL));
POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
|| RETVAL->GetLoadLevel() >= targetLevel);
@@ -2836,16 +2836,16 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
GCX_PREEMP();
// Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
- result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
+ result = FindAssembly(pPEAssembly, FindAssemblyOptions_IncludeFailedToLoad);
if (result == NULL)
{
LoaderAllocator *pLoaderAllocator = NULL;
- AssemblyBinder *pFileBinder = pFile->GetAssemblyBinder();
+ AssemblyBinder *pAssemblyBinder = pPEAssembly->GetAssemblyBinder();
// Assemblies loaded with CustomAssemblyBinder need to use a different LoaderAllocator if
// marked as collectible
- pLoaderAllocator = pFileBinder->GetLoaderAllocator();
+ pLoaderAllocator = pAssemblyBinder->GetLoaderAllocator();
if (pLoaderAllocator == NULL)
{
pLoaderAllocator = this->GetLoaderAllocator();
@@ -2853,22 +2853,22 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
// Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
// a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
- NewHolder pDomainAssembly = new DomainAssembly(this, pFile, pLoaderAllocator);
+ NewHolder pDomainAssembly = new DomainAssembly(this, pPEAssembly, pLoaderAllocator);
LoadLockHolder lock(this);
// Find the list lock entry
- FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
+ FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pPEAssembly);
bool registerNewAssembly = false;
if (fileLock == NULL)
{
// Check again in case we were racing
- result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
+ result = FindAssembly(pPEAssembly, FindAssemblyOptions_IncludeFailedToLoad);
if (result == NULL)
{
// We are the first one in - create the DomainAssembly
registerNewAssembly = true;
- fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
+ fileLock = FileLoadLock::Create(lock, pPEAssembly, pDomainAssembly);
pDomainAssembly.SuppressRelease();
if (pDomainAssembly->IsCollectible())
{
@@ -2901,7 +2901,7 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
if (registerNewAssembly)
{
- pFile->GetAssemblyBinder()->AddLoadedAssembly(pDomainAssembly->GetCurrentAssembly());
+ pPEAssembly->GetAssemblyBinder()->AddLoadedAssembly(pDomainAssembly->GetCurrentAssembly());
}
}
else
@@ -2915,11 +2915,11 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
ThrowHR(COR_E_ASSEMBLYEXPECTED);
}
- // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
+ // Cache result in all cases, since found pPEAssembly could be from a different AssemblyRef than pIdentity
if (pIdentity == NULL)
{
AssemblySpec spec;
- spec.InitializeSpec(result->GetFile());
+ spec.InitializeSpec(result->GetPEAssembly());
GetAppDomain()->AddAssemblyToCache(&spec, result);
}
else
@@ -2956,26 +2956,6 @@ DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetL
// Make sure we release the lock on exit
FileLoadLockRefHolder lockRef(pLock);
- // We need to perform the early steps of loading CoreLib without a domain transition. This is
- // important for bootstrapping purposes - we need to get CoreLib at least partially loaded
- // into a domain before we can run serialization code to do the transition.
- //
- // Note that we cannot do this in general for all assemblies, because some of the security computations
- // require the managed exposed object, which must be created in the correct app domain.
-
- if (this != GetAppDomain()
- && pFile->GetFile()->IsSystem()
- && targetLevel > FILE_LOAD_ALLOCATE)
- {
- // Re-call the routine with a limited load level. This will cause the first part of the load to
- // get performed in the current app domain.
-
- pLock->AddRef();
- LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
-
- // Now continue on to complete the rest of the load, if any.
- }
-
// Do a quick out check for the already loaded case.
if (pLock->GetLoadLevel() >= targetLevel)
{
@@ -3151,7 +3131,7 @@ void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, F
}
if (!EEFileLoadException::CheckType(pEx))
- EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
+ EEFileLoadException::Throw(pFile->GetPEAssembly(), pEx->GetHR(), pEx);
}
// Otherwise, we simply abort this load, and can retry later on.
@@ -3212,7 +3192,7 @@ void AppDomain::SetupSharedStatics()
SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString());
}
-DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
+DomainAssembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
{
CONTRACTL
{
@@ -3225,9 +3205,9 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions
const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
- if (pFile->HasHostAssembly())
+ if (pPEAssembly->HasHostAssembly())
{
- DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
+ DomainAssembly * pDA = FindAssembly(pPEAssembly->GetHostAssembly());
if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
{
return pDA;
@@ -3243,10 +3223,9 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions
while (i.Next(pDomainAssembly.This()))
{
- PEFile * pManifestFile = pDomainAssembly->GetFile();
+ PEAssembly * pManifestFile = pDomainAssembly->GetPEAssembly();
if (pManifestFile &&
- !pManifestFile->IsResource() &&
- pManifestFile->Equals(pFile))
+ pManifestFile->Equals(pPEAssembly))
{
// Caller already has PEAssembly, so we can give DomainAssembly away freely without added reference
return pDomainAssembly.GetValue();
@@ -3412,7 +3391,7 @@ PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
#ifndef DACCESS_COMPILE
-BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
+BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly * pPEAssembly, BOOL fAllowFailure)
{
CONTRACTL
{
@@ -3428,7 +3407,7 @@ BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAll
DomainCacheCrstHolderForGCCoop holder(this);
// !!! suppress exceptions
- if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
+ if(!m_AssemblyCache.StorePEAssembly(pSpec, pPEAssembly) && !fAllowFailure)
{
// TODO: Disabling the below assertion as currently we experience
// inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
@@ -3538,17 +3517,17 @@ NATIVE_LIBRARY_HANDLE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
RETURN existingEntry->Handle;
}
-BOOL AppDomain::RemoveFileFromCache(PEAssembly *pFile)
+BOOL AppDomain::RemoveFileFromCache(PEAssembly * pPEAssembly)
{
CONTRACTL
{
GC_TRIGGERS;
- PRECONDITION(CheckPointer(pFile));
+ PRECONDITION(CheckPointer(pPEAssembly));
}
CONTRACTL_END;
LoadLockHolder lock(this);
- FileLoadLock *fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
+ FileLoadLock *fileLock = (FileLoadLock *)lock->FindFileLock(pPEAssembly);
if (fileLock == NULL)
return FALSE;
@@ -3611,9 +3590,9 @@ PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/
if (fThrow && pSpec->IsCoreLib())
{
CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
- PEAssembly *pFile = SystemDomain::System()->SystemFile();
- pFile->AddRef();
- return pFile;
+ PEAssembly * pPEAssembly = SystemDomain::System()->SystemPEAssembly();
+ pPEAssembly->AddRef();
+ return pPEAssembly;
}
return m_AssemblyCache.LookupFile(pSpec, fThrow);
@@ -3697,16 +3676,16 @@ PEAssembly * AppDomain::BindAssemblySpec(
if (boundAssembly)
{
- if (SystemDomain::SystemFile() && boundAssembly->GetAssemblyName()->IsCoreLib())
+ if (SystemDomain::SystemPEAssembly() && boundAssembly->GetAssemblyName()->IsCoreLib())
{
// Avoid rebinding to another copy of CoreLib
- result = SystemDomain::SystemFile();
+ result = SystemDomain::SystemPEAssembly();
result.SuppressRelease(); // Didn't get a refcount
}
else
{
- // IsSystem on the PEFile should be false, even for CoreLib satellites
- result = PEAssembly::Open(boundAssembly, FALSE);
+ // IsSystem on the PEAssembly should be false, even for CoreLib satellites
+ result = PEAssembly::Open(boundAssembly);
}
// Setup the reference to the binder, which performed the bind, into the AssemblySpec
@@ -3861,9 +3840,9 @@ PEAssembly *AppDomain::TryResolveAssemblyUsingEvent(AssemblySpec *pSpec)
Assembly *pAssembly = RaiseAssemblyResolveEvent(pSpec);
if (pAssembly != nullptr)
{
- PEAssembly *pFile = pAssembly->GetManifestFile();
- pFile->AddRef();
- result = pFile;
+ PEAssembly* pPEAssembly = pAssembly->GetManifestFile();
+ pPEAssembly->AddRef();
+ result = pPEAssembly;
}
BinderTracing::ResolutionAttemptedOperation::TraceAppDomainAssemblyResolve(pSpec, result);
@@ -3924,7 +3903,7 @@ void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
}
CONTRACTL_END;
- if (pAssembly->GetFile()->IsSystem())
+ if (pAssembly->GetPEAssembly()->IsSystem())
{
return;
}
@@ -4040,7 +4019,7 @@ AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pThrowable, BOOL isTerminatin
}
-DefaultAssemblyBinder *AppDomain::CreateBinderContext()
+DefaultAssemblyBinder *AppDomain::CreateDefaultBinder()
{
CONTRACT(DefaultAssemblyBinder *)
{
@@ -5138,7 +5117,7 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB
}
else
{
- pLoadedPEAssembly = pDomainAssembly->GetFile();
+ pLoadedPEAssembly = pDomainAssembly->GetPEAssembly();
if (!pLoadedPEAssembly->HasHostAssembly())
{
// Reflection emitted assemblies will not have a domain assembly.
@@ -5300,9 +5279,9 @@ SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
}
BaseDomain::EnumMemoryRegions(flags, false);
- if (m_pSystemFile.IsValid())
+ if (m_pSystemPEAssembly.IsValid())
{
- m_pSystemFile->EnumMemoryRegions(flags);
+ m_pSystemPEAssembly->EnumMemoryRegions(flags);
}
if (m_pSystemAssembly.IsValid())
{
@@ -5372,11 +5351,11 @@ void AppDomain::PublishHostedAssembly(
}
CONTRACTL_END
- if (pDomainAssembly->GetFile()->HasHostAssembly())
+ if (pDomainAssembly->GetPEAssembly()->HasHostAssembly())
{
// We have to serialize all Add operations
CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
- _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
+ _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetPEAssembly()->GetHostAssembly()) == nullptr);
// Wrapper for m_hostAssemblyMap.Add that avoids call out into host
HostAssemblyMap::AddPhases addCall;
@@ -5401,75 +5380,6 @@ void AppDomain::PublishHostedAssembly(
}
}
-//---------------------------------------------------------------------------------------------------------------------
-void AppDomain::UpdatePublishHostedAssembly(
- DomainAssembly * pAssembly,
- PTR_PEFile pFile)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END
-
- if (pAssembly->GetFile()->HasHostAssembly())
- {
- // We have to serialize all Add operations
- CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
- {
- // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
- OriginalFileHostAssemblyMap::AddPhases addCall;
- bool fAddOrigFile = false;
-
- // For cases where the pefile is being updated
- // 1. Preallocate one element
- if (pFile != pAssembly->GetFile())
- {
- addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
- fAddOrigFile = true;
- }
-
- {
- // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
- ForbidSuspendThreadHolder suspend;
- {
- CrstHolder lock(&m_crstHostAssemblyMap);
-
- // Remove from hash table.
- _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
- m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
-
- // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
- pAssembly->UpdatePEFileWorker(pFile);
-
- _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
- if (fAddOrigFile)
- {
- // Add to the orig file hash table if we might be in a case where we've cached the original pefile and not the final pe file (for use during GetAssemblyIfLoaded)
- addCall.Add(pAssembly);
- }
-
- // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
- _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
- m_hostAssemblyMap.Add(pAssembly);
- }
- }
-
- // 4. Cleanup the old memory (if any)
- if (fAddOrigFile)
- addCall.DeleteOldTable();
- }
- }
- else
- {
-
- pAssembly->UpdatePEFileWorker(pFile);
- }
-}
-
//---------------------------------------------------------------------------------------------------------------------
void AppDomain::UnPublishHostedAssembly(
DomainAssembly * pAssembly)
@@ -5483,19 +5393,13 @@ void AppDomain::UnPublishHostedAssembly(
}
CONTRACTL_END
- if (pAssembly->GetFile()->HasHostAssembly())
+ if (pAssembly->GetPEAssembly()->HasHostAssembly())
{
ForbidSuspendThreadHolder suspend;
{
CrstHolder lock(&m_crstHostAssemblyMap);
- _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
- m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
-
- // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
- if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
- {
- m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
- }
+ _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetPEAssembly()->GetHostAssembly()) != nullptr);
+ m_hostAssemblyMap.Remove(pAssembly->GetPEAssembly()->GetHostAssembly());
}
}
}
@@ -5521,18 +5425,7 @@ PTR_DomainAssembly AppDomain::FindAssembly(PTR_BINDER_SPACE_Assembly pHostAssemb
ForbidSuspendThreadHolder suspend;
{
CrstHolder lock(&m_crstHostAssemblyMap);
- PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
- if (returnValue == NULL)
- {
- // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
- // This is necessary as it may happen during in a second AppDomain that the PEFile
- // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
- // will in some cases find the pHostAssembly associated with this no longer used PEFile
- // instead of the PEFile that was finally decided upon.
- returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
- }
-
- return returnValue;
+ return m_hostAssemblyMap.Lookup(pHostAssembly);
}
}
}
diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp
index d31dc9af6d8ab..27509c601e4cc 100644
--- a/src/coreclr/vm/appdomain.hpp
+++ b/src/coreclr/vm/appdomain.hpp
@@ -700,7 +700,7 @@ class PEFileListLock : public ListLock
{
public:
#ifndef DACCESS_COMPILE
- ListLockEntry *FindFileLock(PEFile *pFile)
+ ListLockEntry *FindFileLock(PEAssembly *pPEAssembly)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
@@ -714,7 +714,7 @@ class PEFileListLock : public ListLock
pEntry != NULL;
pEntry = pEntry->m_pNext)
{
- if (((PEFile *)pEntry->m_data)->Equals(pFile))
+ if (((PEAssembly *)pEntry->m_data)->Equals(pPEAssembly))
{
return pEntry;
}
@@ -777,7 +777,7 @@ class FileLoadLock : public ListLockEntry
HRESULT m_cachedHR;
public:
- static FileLoadLock *Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
+ static FileLoadLock *Create(PEFileListLock *pLock, PEAssembly *pPEAssembly, DomainFile *pDomainFile);
~FileLoadLock();
DomainFile *GetDomainFile();
@@ -807,7 +807,7 @@ class FileLoadLock : public ListLockEntry
private:
- FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
+ FileLoadLock(PEFileListLock *pLock, PEAssembly *pPEAssembly, DomainFile *pDomainFile);
static void HolderLeave(FileLoadLock *pThis);
@@ -1812,11 +1812,11 @@ class AppDomain : public BaseDomain
FindAssemblyOptions_IncludeFailedToLoad = 0x1
};
- DomainAssembly * FindAssembly(PEAssembly * pFile, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL);
+ DomainAssembly * FindAssembly(PEAssembly* pPEAssembly, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL);
Assembly *LoadAssembly(AssemblySpec* pIdentity,
- PEAssembly *pFile,
+ PEAssembly *pPEAssembly,
FileLoadLevel targetLevel);
// this function does not provide caching, you must use LoadDomainAssembly
@@ -1826,11 +1826,11 @@ class AppDomain : public BaseDomain
// resulting in multiple DomainAssembly objects that share the same PEAssembly for ngen image
//which is violating our internal assumptions
DomainAssembly *LoadDomainAssemblyInternal( AssemblySpec* pIdentity,
- PEAssembly *pFile,
+ PEAssembly *pPEAssembly,
FileLoadLevel targetLevel);
DomainAssembly *LoadDomainAssembly( AssemblySpec* pIdentity,
- PEAssembly *pFile,
+ PEAssembly *pPEAssembly,
FileLoadLevel targetLevel);
@@ -1859,8 +1859,8 @@ class AppDomain : public BaseDomain
BOOL IsCached(AssemblySpec *pSpec);
#endif // DACCESS_COMPILE
- BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure = FALSE);
- BOOL RemoveFileFromCache(PEAssembly *pFile);
+ BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pPEAssembly, BOOL fAllowFailure = FALSE);
+ BOOL RemoveFileFromCache(PEAssembly *pPEAssembly);
BOOL AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly);
BOOL RemoveAssemblyFromCache(DomainAssembly* pAssembly);
@@ -1974,7 +1974,7 @@ class AppDomain : public BaseDomain
return m_tpIndex;
}
- DefaultAssemblyBinder *CreateBinderContext();
+ DefaultAssemblyBinder *CreateDefaultBinder();
void SetIgnoreUnhandledExceptions()
{
@@ -2364,7 +2364,7 @@ class AppDomain : public BaseDomain
//-----------------------------------------------------------
// Static BINDER_SPACE::Assembly -> DomainAssembly mapping functions.
// This map does not maintain a reference count to either key or value.
- // PEFile maintains a reference count on the BINDER_SPACE::Assembly through its code:PEFile::m_pHostAssembly field.
+ // PEAssembly maintains a reference count on the BINDER_SPACE::Assembly through its code:PEAssembly::m_pHostAssembly field.
// It is removed from this hash table by code:DomainAssembly::~DomainAssembly.
struct HostAssemblyHashTraits : public DefaultSHashTraits
{
@@ -2374,7 +2374,7 @@ class AppDomain : public BaseDomain
static key_t GetKey(element_t const & elem)
{
STATIC_CONTRACT_WRAPPER;
- return elem->GetFile()->GetHostAssembly();
+ return elem->GetPEAssembly()->GetHostAssembly();
}
static BOOL Equals(key_t key1, key_t key2)
@@ -2396,20 +2396,8 @@ class AppDomain : public BaseDomain
static bool IsDeleted(const element_t & e) { return dac_cast(e) == (TADDR)-1; }
};
- struct OriginalFileHostAssemblyHashTraits : public HostAssemblyHashTraits
- {
- public:
- static key_t GetKey(element_t const & elem)
- {
- STATIC_CONTRACT_WRAPPER;
- return elem->GetOriginalFile()->GetHostAssembly();
- }
- };
-
typedef SHash HostAssemblyMap;
- typedef SHash OriginalFileHostAssemblyMap;
HostAssemblyMap m_hostAssemblyMap;
- OriginalFileHostAssemblyMap m_hostAssemblyMapForOrigFile;
CrstExplicitInit m_crstHostAssemblyMap;
// Lock to serialize all Add operations (in addition to the "read-lock" above)
CrstExplicitInit m_crstHostAssemblyMapAdd;
@@ -2427,11 +2415,6 @@ class AppDomain : public BaseDomain
void PublishHostedAssembly(
DomainAssembly* pAssembly);
- // Called from DomainAssembly::UpdatePEFile.
- void UpdatePublishHostedAssembly(
- DomainAssembly* pAssembly,
- PTR_PEFile pFile);
-
// Called from DomainAssembly::~DomainAssembly
void UnPublishHostedAssembly(
DomainAssembly* pAssembly);
@@ -2512,12 +2495,12 @@ class SystemDomain : public BaseDomain
return m_pSystemDomain;
}
- static PEAssembly* SystemFile()
+ static PEAssembly* SystemPEAssembly()
{
WRAPPER_NO_CONTRACT;
_ASSERTE(m_pSystemDomain);
- return System()->m_pSystemFile;
+ return System()->m_pSystemPEAssembly;
}
static Assembly* SystemAssembly()
@@ -2708,7 +2691,7 @@ class SystemDomain : public BaseDomain
}
#endif
- PTR_PEAssembly m_pSystemFile; // Single assembly (here for quicker reference);
+ PTR_PEAssembly m_pSystemPEAssembly;// Single assembly (here for quicker reference);
PTR_Assembly m_pSystemAssembly; // Single assembly (here for quicker reference);
GlobalLoaderAllocator m_GlobalAllocator;
diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp
index c0fe297fc1ecc..754cf91696ff7 100644
--- a/src/coreclr/vm/assembly.cpp
+++ b/src/coreclr/vm/assembly.cpp
@@ -62,9 +62,56 @@
#ifndef DACCESS_COMPILE
volatile uint32_t g_cAssemblies = 0;
-
static CrstStatic g_friendAssembliesCrst;
+namespace
+{
+ void DefineEmitScope(GUID iid, void** ppEmit)
+ {
+ CONTRACT_VOID
+ {
+ PRECONDITION(CheckPointer(ppEmit));
+ POSTCONDITION(CheckPointer(*ppEmit));
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACT_END;
+
+ SafeComHolder pDispenser;
+
+ // Get the Dispenser interface.
+ MetaDataGetDispenser(
+ CLSID_CorMetaDataDispenser,
+ IID_IMetaDataDispenserEx,
+ (void**)&pDispenser);
+ if (pDispenser == NULL)
+ {
+ ThrowOutOfMemory();
+ }
+
+ // Set the option on the dispenser turn on duplicate check for TypeDef and moduleRef
+ VARIANT varOption;
+ V_VT(&varOption) = VT_UI4;
+ V_I4(&varOption) = MDDupDefault | MDDupTypeDef | MDDupModuleRef | MDDupExportedType | MDDupAssemblyRef | MDDupPermission | MDDupFile;
+ IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &varOption));
+
+ // Set minimal MetaData size
+ V_VT(&varOption) = VT_UI4;
+ V_I4(&varOption) = MDInitialSizeMinimal;
+ IfFailThrow(pDispenser->SetOption(MetaDataInitialSize, &varOption));
+
+ // turn on the thread safety!
+ V_I4(&varOption) = MDThreadSafetyOn;
+ IfFailThrow(pDispenser->SetOption(MetaDataThreadSafetyOptions, &varOption));
+
+ IfFailThrow(pDispenser->DefineScope(CLSID_CorMetaDataRuntime, 0, iid, (IUnknown**)ppEmit));
+
+ RETURN;
+ }
+}
+
void Assembly::Initialize()
{
g_friendAssembliesCrst.Init(CrstLeafLock);
@@ -75,12 +122,12 @@ void Assembly::Initialize()
// It cannot do any allocations or operations that might fail. Those operations should be done
// in Assembly::Init()
//----------------------------------------------------------------------------------------------
-Assembly::Assembly(BaseDomain *pDomain, PEAssembly* pFile, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible) :
+Assembly::Assembly(BaseDomain *pDomain, PEAssembly* pPEAssembly, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible) :
m_pDomain(pDomain),
m_pClassLoader(NULL),
m_pEntryPoint(NULL),
m_pManifest(NULL),
- m_pManifestFile(clr::SafeAddRef(pFile)),
+ m_pManifestFile(clr::SafeAddRef(pPEAssembly)),
m_pFriendAssemblyDescriptor(NULL),
m_isDynamic(false),
#ifdef FEATURE_COLLECTIBLE_TYPES
@@ -164,7 +211,7 @@ void Assembly::Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocat
if (IsCollectible())
{
COUNT_T size;
- BYTE *start = (BYTE*)m_pManifest->GetFile()->GetLoadedImageContents(&size);
+ BYTE *start = (BYTE*)m_pManifest->GetPEAssembly()->GetLoadedImageContents(&size);
if (start != NULL)
{
GCX_COOP();
@@ -381,14 +428,14 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
// Set up the assembly manifest metadata
// When we create dynamic assembly, we always use a working copy of IMetaDataAssemblyEmit
// to store temporary runtime assembly information. This is to preserve the invariant that
- // an assembly must have a PEFile with proper metadata.
+ // an assembly must have a PEAssembly with proper metadata.
// This working copy of IMetaDataAssemblyEmit will store every AssemblyRef as a simple name
// reference as we must have an instance of Assembly(can be dynamic assembly) before we can
// add such a reference. Also because the referenced assembly if dynamic strong name, it may
// not be ready to be hashed!
SafeComHolder pAssemblyEmit;
- PEFile::DefineEmitScope(
+ DefineEmitScope(
IID_IMetaDataAssemblyEmit,
&pAssemblyEmit);
@@ -453,7 +500,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
DWORD dwFlags = args->assemblyName->GetFlags();
// Now create a dynamic PE file out of the name & metadata
- PEAssemblyHolder pFile;
+ PEAssemblyHolder pPEAssembly;
{
GCX_PREEMP();
@@ -462,7 +509,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
IfFailThrow(pAssemblyEmit->DefineAssembly(publicKey, publicKey.GetSize(), ulHashAlgId,
name, &assemData, dwFlags,
&ma));
- pFile = PEAssembly::Create(pCallerAssembly->GetManifestFile(), pAssemblyEmit);
+ pPEAssembly = PEAssembly::Create(pCallerAssembly->GetManifestFile(), pAssemblyEmit);
AssemblyBinder* pFallbackBinder = pBinder;
@@ -477,7 +524,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
// and will have a fallback load context binder associated with it.
// There is always a manifest file - wehther working with static or dynamic assemblies.
- PEFile* pCallerAssemblyManifestFile = pCallerAssembly->GetManifestFile();
+ PEAssembly* pCallerAssemblyManifestFile = pCallerAssembly->GetManifestFile();
_ASSERTE(pCallerAssemblyManifestFile != NULL);
if (!pCallerAssemblyManifestFile->IsDynamic())
@@ -503,7 +550,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
_ASSERTE(pFallbackBinder != nullptr);
// Set it as the fallback load context binder for the dynamic assembly being created
- pFile->SetFallbackBinder(pFallbackBinder);
+ pPEAssembly->SetFallbackBinder(pFallbackBinder);
}
NewHolder pDomainAssembly;
@@ -551,7 +598,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
}
// Create a domain assembly
- pDomainAssembly = new DomainAssembly(pDomain, pFile, pLoaderAllocator);
+ pDomainAssembly = new DomainAssembly(pDomain, pPEAssembly, pLoaderAllocator);
if (pDomainAssembly->IsCollectible())
{
// We add the assembly to the LoaderAllocator only when we are sure that it can be added
@@ -569,7 +616,7 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, AssemblyBinder* pBinder, C
{
GCX_PREEMP();
// Assembly::Create will call SuppressRelease on the NewHolder that holds the LoaderAllocator when it transfers ownership
- pAssem = Assembly::Create(pDomain, pFile, pDomainAssembly->GetDebuggerInfoBits(), pLoaderAllocator->IsCollectible(), pamTracker, pLoaderAllocator);
+ pAssem = Assembly::Create(pDomain, pPEAssembly, pDomainAssembly->GetDebuggerInfoBits(), pLoaderAllocator->IsCollectible(), pamTracker, pLoaderAllocator);
ReflectionModule* pModule = (ReflectionModule*) pAssem->GetManifestModule();
pModule->SetCreatingAssembly( pCallerAssembly );
@@ -817,7 +864,7 @@ Module *Assembly::FindModuleByExportedType(mdExportedType mdType,
// Note that we don't want to attempt a LoadModule if a GetModuleIfLoaded will
// succeed, because it has a stronger contract.
- Module *pModule = GetManifestModule()->GetModuleIfLoaded(mdLinkRef, TRUE, FALSE);
+ Module *pModule = GetManifestModule()->GetModuleIfLoaded(mdLinkRef);
#ifdef DACCESS_COMPILE
return pModule;
#else
@@ -830,7 +877,11 @@ Module *Assembly::FindModuleByExportedType(mdExportedType mdType,
// We should never get here in the GC case - the above should have succeeded.
CONSISTENCY_CHECK(!FORBIDGC_LOADER_USE_ENABLED());
- DomainFile * pDomainModule = GetManifestModule()->LoadModule(::GetAppDomain(), mdLinkRef, FALSE, loadFlag!=Loader::Load);
+ DomainFile* pDomainModule = NULL;
+ if (loadFlag == Loader::Load)
+ {
+ pDomainModule = GetManifestModule()->LoadModule(::GetAppDomain(), mdLinkRef);
+ }
if (pDomainModule == NULL)
RETURN NULL;
@@ -953,18 +1004,18 @@ Module * Assembly::FindModuleByTypeRef(
// Either we're not supposed to load, or we're doing a GC or stackwalk
// in which case we shouldn't need to load. So just look up the module
// and return what we find.
- RETURN(pModule->LookupModule(tkType,FALSE));
+ RETURN(pModule->LookupModule(tkType));
}
#ifndef DACCESS_COMPILE
- DomainFile * pActualDomainFile = pModule->LoadModule(::GetAppDomain(), tkType, FALSE, loadFlag!=Loader::Load);
- if (pActualDomainFile == NULL)
+ if (loadFlag == Loader::Load)
{
- RETURN NULL;
+ DomainFile* pActualDomainFile = pModule->LoadModule(::GetAppDomain(), tkType);
+ RETURN(pActualDomainFile->GetModule());
}
else
{
- RETURN(pActualDomainFile->GetModule());
+ RETURN NULL;
}
#else //DACCESS_COMPILE
@@ -1056,7 +1107,7 @@ Module *Assembly::FindModuleByName(LPCSTR pszModuleName)
ThrowHR(COR_E_UNAUTHORIZEDACCESS);
if (this == SystemDomain::SystemAssembly())
- RETURN m_pManifest->GetModuleIfLoaded(kFile, TRUE, TRUE);
+ RETURN m_pManifest->GetModuleIfLoaded(kFile);
else
RETURN m_pManifest->LoadModule(::GetAppDomain(), kFile)->GetModule();
}
@@ -1124,7 +1175,7 @@ void Assembly::PrepareModuleForAssembly(Module* module, AllocMemTracker *pamTrac
module->SetDebuggerInfoBits(GetDebuggerInfoBits());
LOG((LF_CORDB, LL_INFO10, "Module %s: bits=0x%x\n",
- module->GetFile()->GetSimpleName(),
+ module->GetPEAssembly()->GetSimpleName(),
module->GetDebuggerInfoBits()));
#endif // DEBUGGING_SUPPORTED
@@ -1648,7 +1699,7 @@ MethodDesc* Assembly::GetEntryPoint()
Module *pModule = NULL;
switch(TypeFromToken(mdEntry)) {
case mdtFile:
- pModule = m_pManifest->LoadModule(::GetAppDomain(), mdEntry, FALSE)->GetModule();
+ pModule = m_pManifest->LoadModule(::GetAppDomain(), mdEntry)->GetModule();
mdEntry = pModule->GetEntryPointToken();
if ( (TypeFromToken(mdEntry) != mdtMethodDef) ||
@@ -1657,7 +1708,7 @@ MethodDesc* Assembly::GetEntryPoint()
break;
case mdtMethodDef:
- if (m_pManifestFile->GetPersistentMDImport()->IsValidToken(mdEntry))
+ if (m_pManifestFile->GetMDImport()->IsValidToken(mdEntry))
pModule = m_pManifest;
break;
}
@@ -2240,7 +2291,7 @@ ReleaseHolder FriendAssemblyDescriptor::CreateFriendAs
ReleaseHolder pFriendAssemblies = new FriendAssemblyDescriptor;
// We're going to do this twice, once for InternalsVisibleTo and once for IgnoresAccessChecks
- ReleaseHolder pImport(pAssembly->GetMDImportWithRef());
+ IMDInternalImport* pImport = pAssembly->GetMDImport();
for(int count = 0 ; count < 2 ; ++count)
{
_ASSERTE(pImport != NULL);
diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp
index db972f0ccf149..f8de5c162e752 100644
--- a/src/coreclr/vm/assembly.hpp
+++ b/src/coreclr/vm/assembly.hpp
@@ -79,13 +79,13 @@ class Assembly
friend class ClrDataAccess;
public:
- Assembly(BaseDomain *pDomain, PEAssembly *pFile, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible);
+ Assembly(BaseDomain *pDomain, PEAssembly *pPEAssembly, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible);
void Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocator);
void StartUnload();
void Terminate( BOOL signalProfiler = TRUE );
- static Assembly *Create(BaseDomain *pDomain, PEAssembly *pFile, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible, AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocator);
+ static Assembly *Create(BaseDomain *pDomain, PEAssembly *pPEAssembly, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible, AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocator);
static void Initialize();
BOOL IsSystem() { WRAPPER_NO_CONTRACT; return m_pManifestFile->IsSystem(); }
@@ -299,7 +299,7 @@ class Assembly
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- return m_pManifestFile->GetPersistentMDImport();
+ return m_pManifestFile->GetMDImport();
}
HRESULT GetCustomAttribute(mdToken parentToken,
@@ -312,14 +312,6 @@ class Assembly
return GetManifestModule()->GetCustomAttribute(parentToken, attribute, ppData, pcbData);
}
-#ifndef DACCESS_COMPILE
- IMetaDataAssemblyImport* GetManifestAssemblyImporter()
- {
- WRAPPER_NO_CONTRACT;
- return m_pManifestFile->GetAssemblyImporter();
- }
-#endif // DACCESS_COMPILE
-
mdAssembly GetManifestToken()
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/coreclr/vm/assemblybinder.cpp b/src/coreclr/vm/assemblybinder.cpp
index 1ce6d2e93beb1..2e231741efbd3 100644
--- a/src/coreclr/vm/assemblybinder.cpp
+++ b/src/coreclr/vm/assemblybinder.cpp
@@ -32,7 +32,7 @@ NativeImage* AssemblyBinder::LoadNativeImage(Module* componentModule, LPCUTF8 na
STANDARD_VM_CONTRACT;
BaseDomain::LoadLockHolder lock(AppDomain::GetCurrentDomain());
- AssemblyBinder* binder = componentModule->GetFile()->GetAssemblyBinder();
+ AssemblyBinder* binder = componentModule->GetPEAssembly()->GetAssemblyBinder();
PTR_LoaderAllocator moduleLoaderAllocator = componentModule->GetLoaderAllocator();
bool isNewNativeImage;
diff --git a/src/coreclr/vm/assemblyname.cpp b/src/coreclr/vm/assemblyname.cpp
index 0983c80715fae..c04a01408bbf8 100644
--- a/src/coreclr/vm/assemblyname.cpp
+++ b/src/coreclr/vm/assemblyname.cpp
@@ -56,7 +56,7 @@ FCIMPL1(Object*, AssemblyNameNative::GetFileInformation, StringObject* filenameU
// waiting for it to happen during HasNTHeaders. This allows us to
// get the assembly name for images that contain native code for a
// non-native platform.
- PEImageLayoutHolder pLayout(pImage->GetLayout(PEImageLayout::LAYOUT_FLAT, PEImage::LAYOUT_CREATEIFNEEDED));
+ PEImageLayout* pLayout = pImage->GetOrCreateLayout(PEImageLayout::LAYOUT_FLAT);
pImage->VerifyIsAssembly();
diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp
index 37d27fb1a9c25..a67c9e5c4c0b6 100644
--- a/src/coreclr/vm/assemblynative.cpp
+++ b/src/coreclr/vm/assemblynative.cpp
@@ -108,7 +108,7 @@ void QCALLTYPE AssemblyNative::InternalLoad(QCall::ObjectHandleOnStack assemblyN
{
// If the requesting assembly has Fallback LoadContext binder available,
// then set it up in the AssemblySpec.
- PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile();
+ PEAssembly *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile();
spec.SetFallbackBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackBinder());
}
@@ -157,7 +157,7 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma
// Set the caller's assembly to be CoreLib
DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly();
- PEAssembly *pParentAssembly = pCallersAssembly->GetFile();
+ PEAssembly *pParentAssembly = pCallersAssembly->GetPEAssembly();
// Initialize the AssemblySpec
AssemblySpec spec;
@@ -289,7 +289,7 @@ void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyBinder, I
// we created above. We need pointer comparison instead of pe image equivalence
// to avoid mixed binaries/PDB pairs of other images.
// This applies to both Desktop CLR and CoreCLR, with or without fusion.
- BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetILimage() == pILImage);
+ BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetPEImage() == pILImage);
// Setting the PDB info is only applicable for our original assembly.
// This applies to both Desktop CLR and CoreCLR, with or without fusion.
@@ -351,7 +351,7 @@ void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCal
BEGIN_QCALL;
{
- retString.Set(pAssembly->GetFile()->GetPath());
+ retString.Set(pAssembly->GetPEAssembly()->GetPath());
}
END_QCALL;
@@ -449,7 +449,7 @@ FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNS
if (refAssembly == NULL)
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
- FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetFile()->IsDynamic());
+ FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetPEAssembly()->IsDynamic());
}
FCIMPLEND
@@ -461,7 +461,7 @@ void QCALLTYPE AssemblyNative::GetVersion(QCall::AssemblyHandle pAssembly, INT32
UINT16 major=0xffff, minor=0xffff, build=0xffff, revision=0xffff;
- pAssembly->GetFile()->GetVersion(&major, &minor, &build, &revision);
+ pAssembly->GetPEAssembly()->GetVersion(&major, &minor, &build, &revision);
*pMajorVersion = major;
*pMinorVersion = minor;
@@ -478,7 +478,7 @@ void QCALLTYPE AssemblyNative::GetPublicKey(QCall::AssemblyHandle pAssembly, QCa
BEGIN_QCALL;
DWORD cbPublicKey = 0;
- const void *pbPublicKey = pAssembly->GetFile()->GetPublicKey(&cbPublicKey);
+ const void *pbPublicKey = pAssembly->GetPEAssembly()->GetPublicKey(&cbPublicKey);
retPublicKey.SetByteArray((BYTE *)pbPublicKey, cbPublicKey);
END_QCALL;
@@ -499,7 +499,7 @@ void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall:
BEGIN_QCALL;
- LPCUTF8 pLocale = pAssembly->GetFile()->GetLocale();
+ LPCUTF8 pLocale = pAssembly->GetPEAssembly()->GetLocale();
if(pLocale)
{
retString.Set(pLocale);
@@ -519,7 +519,7 @@ BOOL QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, QCal
StackSString codebase;
{
- ret = pAssembly->GetFile()->GetCodeBase(codebase);
+ ret = pAssembly->GetPEAssembly()->GetCodeBase(codebase);
}
retString.Set(codebase);
@@ -534,7 +534,7 @@ INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly
INT32 retVal=0;
BEGIN_QCALL;
- retVal = pAssembly->GetFile()->GetHashAlgId();
+ retVal = pAssembly->GetPEAssembly()->GetHashAlgId();
END_QCALL;
return retVal;
}
@@ -545,7 +545,7 @@ INT32 QCALLTYPE AssemblyNative::GetFlags(QCall::AssemblyHandle pAssembly)
INT32 retVal=0;
BEGIN_QCALL;
- retVal = pAssembly->GetFile()->GetFlags();
+ retVal = pAssembly->GetPEAssembly()->GetFlags();
END_QCALL;
return retVal;
}
@@ -639,9 +639,9 @@ void QCALLTYPE AssemblyNative::GetModules(QCall::AssemblyHandle pAssembly, BOOL
mdFile mdFile;
while (pAssembly->GetMDImport()->EnumNext(&phEnum, &mdFile))
{
- DomainFile *pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile, fGetResourceModules, !fLoadIfNotFound);
-
- if (pModule) {
+ if (fLoadIfNotFound)
+ {
+ DomainFile* pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile);
modules.Append(pModule);
}
}
@@ -1065,7 +1065,7 @@ void QCALLTYPE AssemblyNative::GetFullName(QCall::AssemblyHandle pAssembly, QCal
BEGIN_QCALL;
StackSString name;
- pAssembly->GetFile()->GetDisplayName(name);
+ pAssembly->GetPEAssembly()->GetDisplayName(name);
retString.Set(name);
END_QCALL;
@@ -1135,12 +1135,12 @@ void QCALLTYPE AssemblyNative::GetImageRuntimeVersion(QCall::AssemblyHandle pAss
BEGIN_QCALL;
- // Retrieve the PEFile from the assembly.
- PEFile* pPEFile = pAssembly->GetFile();
- PREFIX_ASSUME(pPEFile!=NULL);
+ // Retrieve the PEAssembly from the assembly.
+ PEAssembly* pPEAssembly = pAssembly->GetPEAssembly();
+ PREFIX_ASSUME(pPEAssembly!=NULL);
LPCSTR pszVersion = NULL;
- IfFailThrow(pPEFile->GetMDImport()->GetVersionString(&pszVersion));
+ IfFailThrow(pPEAssembly->GetMDImport()->GetVersionString(&pszVersion));
SString version(SString::Utf8, pszVersion);
@@ -1253,7 +1253,7 @@ INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandl
_ASSERTE(pAssembly != NULL);
- AssemblyBinder* pAssemblyBinder = pAssembly->GetFile()->GetAssemblyBinder();
+ AssemblyBinder* pAssemblyBinder = pAssembly->GetPEAssembly()->GetAssemblyBinder();
if (!pAssemblyBinder->IsDefault())
{
@@ -1284,7 +1284,7 @@ BOOL QCALLTYPE AssemblyNative::InternalTryGetRawMetadata(
_ASSERTE(lengthRef != nullptr);
static_assert_no_msg(sizeof(*lengthRef) == sizeof(COUNT_T));
- metadata = assembly->GetFile()->GetLoadedMetadata(reinterpret_cast(lengthRef));
+ metadata = assembly->GetPEAssembly()->GetLoadedMetadata(reinterpret_cast(lengthRef));
*blobRef = reinterpret_cast(const_cast(metadata));
_ASSERTE(*lengthRef >= 0);
diff --git a/src/coreclr/vm/assemblynative.hpp b/src/coreclr/vm/assemblynative.hpp
index a4ecc62da9a32..6270e5072612e 100644
--- a/src/coreclr/vm/assemblynative.hpp
+++ b/src/coreclr/vm/assemblynative.hpp
@@ -108,7 +108,7 @@ class AssemblyNative
static FCDECL0(uint32_t, GetAssemblyCount);
//
- // PEFile QCalls
+ // PEAssembly QCalls
//
static INT_PTR QCALLTYPE InitializeAssemblyLoadContext(INT_PTR ptrManagedAssemblyLoadContext, BOOL fRepresentsTPALoadContext, BOOL fIsCollectible);
diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp
index af5862a9ac5ff..dfbee7152df19 100644
--- a/src/coreclr/vm/assemblyspec.cpp
+++ b/src/coreclr/vm/assemblyspec.cpp
@@ -231,7 +231,7 @@ void AssemblySpec::InitializeSpec(PEAssembly * pFile)
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;
- ReleaseHolder pImport(pFile->GetMDImportWithRef());
+ IMDInternalImport* pImport = pFile->GetMDImport();
mdAssembly a;
IfFailThrow(pImport->GetAssemblyFromScope(&a));
@@ -690,7 +690,7 @@ AssemblyBinder* AssemblySpec::GetBinderFromParentAssembly(AppDomain *pDomain)
if(pParentDomainAssembly != NULL)
{
// Get the PEAssembly associated with the parent's domain assembly
- PEAssembly *pParentPEAssembly = pParentDomainAssembly->GetFile();
+ PEAssembly *pParentPEAssembly = pParentDomainAssembly->GetPEAssembly();
pParentAssemblyBinder = pParentPEAssembly->GetAssemblyBinder();
}
@@ -754,7 +754,7 @@ DomainAssembly *AssemblySpec::LoadDomainAssembly(FileLoadLevel targetLevel,
if (pAssembly)
{
BinderTracing::AssemblyBindOperation bindOperation(this);
- bindOperation.SetResult(pAssembly->GetFile(), true /*cached*/);
+ bindOperation.SetResult(pAssembly->GetPEAssembly(), true /*cached*/);
pDomain->LoadDomainFile(pAssembly, targetLevel);
RETURN pAssembly;
@@ -1219,7 +1219,7 @@ BOOL AssemblySpecBindingCache::StoreAssembly(AssemblySpec *pSpec, DomainAssembly
UPTR key = (UPTR)pSpec->Hash();
- AssemblyBinder* pBinderContextForLookup = pAssembly->GetFile()->GetAssemblyBinder();
+ AssemblyBinder* pBinderContextForLookup = pAssembly->GetPEAssembly()->GetAssemblyBinder();
key = key ^ (UPTR)pBinderContextForLookup;
if (!pSpec->GetBinder())
@@ -1240,13 +1240,13 @@ BOOL AssemblySpecBindingCache::StoreAssembly(AssemblySpec *pSpec, DomainAssembly
}
entry = abHolder.CreateAssemblyBinding(pHeap);
- entry->Init(pSpec,pAssembly->GetFile(),pAssembly,NULL,pHeap, abHolder.GetPamTracker());
+ entry->Init(pSpec,pAssembly->GetPEAssembly(),pAssembly,NULL,pHeap, abHolder.GetPamTracker());
m_map.InsertValue(key, entry);
abHolder.SuppressRelease();
- STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StoreFile (StoreAssembly): Add cached entry (%p) with PEFile %p",entry,pAssembly->GetFile());
+ STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StorePEAssembly (StoreAssembly): Add cached entry (%p) with PEAssembly %p",entry,pAssembly->GetPEAssembly());
RETURN TRUE;
}
else
@@ -1263,7 +1263,7 @@ BOOL AssemblySpecBindingCache::StoreAssembly(AssemblySpec *pSpec, DomainAssembly
{
// OK if we have have a matching PEAssembly
if (entry->GetFile() != NULL
- && pAssembly->GetFile()->Equals(entry->GetFile()))
+ && pAssembly->GetPEAssembly()->Equals(entry->GetFile()))
{
entry->SetAssembly(pAssembly);
RETURN TRUE;
@@ -1280,7 +1280,7 @@ BOOL AssemblySpecBindingCache::StoreAssembly(AssemblySpec *pSpec, DomainAssembly
// Returns TRUE if add was successful - if FALSE is returned, caller should honor current
// cached value to ensure consistency.
-BOOL AssemblySpecBindingCache::StoreFile(AssemblySpec *pSpec, PEAssembly *pFile)
+BOOL AssemblySpecBindingCache::StorePEAssembly(AssemblySpec *pSpec, PEAssembly *pPEAssembly)
{
CONTRACT(BOOL)
{
@@ -1288,14 +1288,14 @@ BOOL AssemblySpecBindingCache::StoreFile(AssemblySpec *pSpec, PEAssembly *pFile)
THROWS;
GC_TRIGGERS;
MODE_ANY;
- POSTCONDITION((!RETVAL) || (UnsafeContains(this, pSpec) && UnsafeVerifyLookupFile(this, pSpec, pFile)));
+ POSTCONDITION((!RETVAL) || (UnsafeContains(this, pSpec) && UnsafeVerifyLookupFile(this, pSpec, pPEAssembly)));
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACT_END;
UPTR key = (UPTR)pSpec->Hash();
- AssemblyBinder* pBinderContextForLookup = pFile->GetAssemblyBinder();
+ AssemblyBinder* pBinderContextForLookup = pPEAssembly->GetAssemblyBinder();
key = key ^ (UPTR)pBinderContextForLookup;
if (!pSpec->GetBinder())
@@ -1325,12 +1325,12 @@ BOOL AssemblySpecBindingCache::StoreFile(AssemblySpec *pSpec, PEAssembly *pFile)
entry = abHolder.CreateAssemblyBinding(pHeap);
- entry->Init(pSpec,pFile,NULL,NULL,pHeap, abHolder.GetPamTracker());
+ entry->Init(pSpec, pPEAssembly,NULL,NULL,pHeap, abHolder.GetPamTracker());
m_map.InsertValue(key, entry);
abHolder.SuppressRelease();
- STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StoreFile: Add cached entry (%p) with PEFile %p\n", entry, pFile);
+ STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StorePEAssembly: Add cached entry (%p) with PEAssembly %p\n", entry, pPEAssembly);
RETURN TRUE;
}
@@ -1340,7 +1340,7 @@ BOOL AssemblySpecBindingCache::StoreFile(AssemblySpec *pSpec, PEAssembly *pFile)
{
// OK if this is a duplicate
if (entry->GetFile() != NULL
- && pFile->Equals(entry->GetFile()))
+ && pPEAssembly->Equals(entry->GetFile()))
RETURN TRUE;
}
else
@@ -1350,7 +1350,7 @@ BOOL AssemblySpecBindingCache::StoreFile(AssemblySpec *pSpec, PEAssembly *pFile)
entry->ThrowIfError();
}
- STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"Incompatible cached entry found (%p) when adding PEFile %p\n", entry, pFile);
+ STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"Incompatible cached entry found (%p) when adding PEAssembly %p\n", entry, pPEAssembly);
// Invalid cache transition (see above note about state transitions)
RETURN FALSE;
}
@@ -1396,7 +1396,7 @@ BOOL AssemblySpecBindingCache::StoreException(AssemblySpec *pSpec, Exception* pE
m_map.InsertValue(key, entry);
abHolder.SuppressRelease();
- STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StoreFile (StoreException): Add cached entry (%p) with exception %p",entry,pEx);
+ STRESS_LOG2(LF_CLASSLOADER,LL_INFO10,"StorePEAssembly (StoreException): Add cached entry (%p) with exception %p",entry,pEx);
RETURN TRUE;
}
else
diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp
index 63ffac82f6e7a..5d09b5b75a664 100644
--- a/src/coreclr/vm/assemblyspec.hpp
+++ b/src/coreclr/vm/assemblyspec.hpp
@@ -102,7 +102,7 @@ class AssemblySpec : public BaseAssemblySpec
};
- void InitializeSpec(PEAssembly *pFile);
+ void InitializeSpec(PEAssembly* pPEAssembly);
HRESULT InitializeSpec(StackingAllocator* alloc,
ASSEMBLYNAMEREF* pName,
BOOL fParse = TRUE);
@@ -332,8 +332,8 @@ class AssemblySpecBindingCache
{
WRAPPER_NO_CONTRACT;
- if (m_pFile != NULL)
- m_pFile->Release();
+ if (m_pPEAssembly != NULL)
+ m_pPEAssembly->Release();
if (m_exceptionType==EXTYPE_EE)
delete m_pException;
@@ -341,7 +341,7 @@ class AssemblySpecBindingCache
inline DomainAssembly* GetAssembly(){ LIMITED_METHOD_CONTRACT; return m_pAssembly;};
inline void SetAssembly(DomainAssembly* pAssembly){ LIMITED_METHOD_CONTRACT; m_pAssembly=pAssembly;};
- inline PEAssembly* GetFile(){ LIMITED_METHOD_CONTRACT; return m_pFile;};
+ inline PEAssembly* GetFile(){ LIMITED_METHOD_CONTRACT; return m_pPEAssembly;};
inline BOOL IsError(){ LIMITED_METHOD_CONTRACT; return (m_exceptionType!=EXTYPE_NONE);};
// bound to the file, but failed later
@@ -365,7 +365,7 @@ class AssemblySpecBindingCache
default: _ASSERTE(!"Unexpected exception type");
}
};
- inline void Init(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly, Exception* pEx, LoaderHeap *pHeap, AllocMemTracker *pamTracker)
+ inline void Init(AssemblySpec* pSpec, PEAssembly* pPEAssembly, DomainAssembly* pAssembly, Exception* pEx, LoaderHeap *pHeap, AllocMemTracker *pamTracker)
{
CONTRACTL
{
@@ -375,7 +375,7 @@ class AssemblySpecBindingCache
}
CONTRACTL_END;
- InitInternal(pSpec,pFile,pAssembly);
+ InitInternal(pSpec,pPEAssembly,pAssembly);
if (pHeap != NULL)
{
m_spec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED,pHeap, pamTracker);
@@ -444,19 +444,19 @@ class AssemblySpecBindingCache
};
protected:
- inline void InitInternal(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly )
+ inline void InitInternal(AssemblySpec* pSpec, PEAssembly* pPEAssembly, DomainAssembly* pAssembly )
{
WRAPPER_NO_CONTRACT;
m_spec.CopyFrom(pSpec);
- m_pFile = pFile;
- if (m_pFile)
- m_pFile->AddRef();
+ m_pPEAssembly = pPEAssembly;
+ if (m_pPEAssembly)
+ m_pPEAssembly->AddRef();
m_pAssembly = pAssembly;
m_exceptionType=EXTYPE_NONE;
}
AssemblySpec m_spec;
- PEAssembly *m_pFile;
+ PEAssembly *m_pPEAssembly;
DomainAssembly *m_pAssembly;
enum{
EXTYPE_NONE = 0x00000000,
@@ -490,7 +490,7 @@ class AssemblySpecBindingCache
PEAssembly *LookupFile(AssemblySpec *pSpec, BOOL fThrow = TRUE);
BOOL StoreAssembly(AssemblySpec *pSpec, DomainAssembly *pAssembly);
- BOOL StoreFile(AssemblySpec *pSpec, PEAssembly *pFile);
+ BOOL StorePEAssembly(AssemblySpec *pSpec, PEAssembly *pPEAssembly);
BOOL StoreException(AssemblySpec *pSpec, Exception* pEx);
diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp
index 3ffb9a83b1511..02374e18df61c 100644
--- a/src/coreclr/vm/ceeload.cpp
+++ b/src/coreclr/vm/ceeload.cpp
@@ -214,7 +214,7 @@ void Module::UpdateNewlyAddedTypes()
// R2R pre-computes an export table and tries to avoid populating a class hash at runtime. However the profiler can
// still add new types on the fly by calling here. If that occurs we fallback to the slower path of creating the
// in memory hashtable as usual.
- if (!IsResource() && GetAvailableClassHash() == NULL)
+ if (GetAvailableClassHash() == NULL)
{
// This call will populate the hash tables with anything that is in metadata already.
GetClassLoader()->LazyPopulateCaseSensitiveHashTablesDontHaveLock();
@@ -266,12 +266,9 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr)
if (SetTransientFlagInterlocked(IS_PROFILER_NOTIFIED))
{
// Record how many types are already present
- if (!IsResource())
- {
- m_dwTypeCount = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
- m_dwExportedTypeCount = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
- m_dwCustomAttributeCount = GetMDImport()->GetCountWithTokenKind(mdtCustomAttribute);
- }
+ m_dwTypeCount = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
+ m_dwExportedTypeCount = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
+ m_dwCustomAttributeCount = GetMDImport()->GetCountWithTokenKind(mdtCustomAttribute);
BOOL profilerCallbackHappened = FALSE;
// Notify the profiler, this may cause metadata to be updated
@@ -294,7 +291,7 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr)
// If there are more types than before, add these new types to the
// assembly
- if (profilerCallbackHappened && !IsResource())
+ if (profilerCallbackHappened)
{
UpdateNewlyAddedTypes();
}
@@ -337,7 +334,7 @@ void Module::NotifyEtwLoadFinished(HRESULT hr)
// The constructor phase initializes just enough so that Destruct() can be safely called.
// It cannot throw or fail.
//
-Module::Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file)
+Module::Module(Assembly *pAssembly, mdFile moduleRef, PEAssembly *pPEAssembly)
{
CONTRACTL
{
@@ -351,13 +348,13 @@ Module::Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file)
m_pAssembly = pAssembly;
m_moduleRef = moduleRef;
- m_file = file;
+ m_pPEAssembly = pPEAssembly;
m_dwTransientFlags = CLASSES_FREED;
// Memory allocated on LoaderHeap is zero-filled. Spot-check it here.
_ASSERTE(m_pBinder == NULL);
- file->AddRef();
+ pPEAssembly->AddRef();
}
void Module::InitializeForProfiling()
@@ -457,7 +454,7 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
}
CONTRACTL_END;
- m_pSimpleName = m_file->GetSimpleName();
+ m_pSimpleName = m_pPEAssembly->GetSimpleName();
m_Crst.Init(CrstModule);
m_LookupTableCrst.Init(CrstModuleLookupTable, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
@@ -486,62 +483,56 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
#ifdef FEATURE_READYTORUN
m_pNativeImage = NULL;
- if (!IsResource())
+ if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL)
{
- if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL)
+ m_pNativeImage = m_pReadyToRunInfo->GetNativeImage();
+ if (m_pNativeImage != NULL)
{
- m_pNativeImage = m_pReadyToRunInfo->GetNativeImage();
- if (m_pNativeImage != NULL)
- {
- m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap();
- }
- else
+ m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap();
+ }
+ else
+ {
+ // For composite images, manifest metadata gets loaded as part of the native image
+ COUNT_T cMeta = 0;
+ if (GetPEAssembly()->GetPEImage()->GetNativeManifestMetadata(&cMeta) != NULL)
{
- // For composite images, manifest metadata gets loaded as part of the native image
- COUNT_T cMeta = 0;
- if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL)
- {
- // Load the native assembly import
- GetNativeAssemblyImport(TRUE /* loadAllowed */);
- }
+ // Load the native assembly import
+ GetNativeAssemblyImport(TRUE /* loadAllowed */);
}
}
}
#endif
- // Initialize the instance fields that we need for all non-Resource Modules
- if (!IsResource())
+ // Initialize the instance fields that we need for all Modules
+ if (m_pAvailableClasses == NULL && !IsReadyToRun())
{
- if (m_pAvailableClasses == NULL && !IsReadyToRun())
- {
- m_pAvailableClasses = EEClassHashTable::Create(this,
- GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS,
- FALSE /* bCaseInsensitive */, pamTracker);
- }
+ m_pAvailableClasses = EEClassHashTable::Create(this,
+ GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS,
+ FALSE /* bCaseInsensitive */, pamTracker);
+ }
- if (m_pAvailableParamTypes == NULL)
- {
- m_pAvailableParamTypes = EETypeHashTable::Create(GetLoaderAllocator(), this, PARAMTYPES_HASH_BUCKETS, pamTracker);
- }
+ if (m_pAvailableParamTypes == NULL)
+ {
+ m_pAvailableParamTypes = EETypeHashTable::Create(GetLoaderAllocator(), this, PARAMTYPES_HASH_BUCKETS, pamTracker);
+ }
- if (m_pInstMethodHashTable == NULL)
+ if (m_pInstMethodHashTable == NULL)
+ {
+ m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
+ }
+
+ if (m_pMemberRefToDescHashTable == NULL)
+ {
+ if (IsReflection())
{
- m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
+ m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, MEMBERREF_MAP_INITIAL_SIZE, pamTracker);
}
-
- if(m_pMemberRefToDescHashTable == NULL)
+ else
{
- if (IsReflection())
- {
- m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, MEMBERREF_MAP_INITIAL_SIZE, pamTracker);
- }
- else
- {
- IMDInternalImport * pImport = GetMDImport();
+ IMDInternalImport* pImport = GetMDImport();
- // Get #MemberRefs and create memberrefToDesc hash table
- m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, pImport->GetCountWithTokenKind(mdtMemberRef)+1, pamTracker);
- }
+ // Get #MemberRefs and create memberrefToDesc hash table
+ m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, pImport->GetCountWithTokenKind(mdtMemberRef) + 1, pamTracker);
}
}
@@ -563,7 +554,7 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
InitializeForProfiling();
}
- if (!IsResource() && (m_AssemblyRefByNameTable == NULL))
+ if (m_AssemblyRefByNameTable == NULL)
{
Module::CreateAssemblyRefByNameTable(pamTracker);
}
@@ -744,16 +735,15 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits)
#ifndef DACCESS_COMPILE
/* static */
-Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEFile *file, AllocMemTracker *pamTracker)
+Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEAssembly *pPEAssembly, AllocMemTracker *pamTracker)
{
CONTRACT(Module *)
{
STANDARD_VM_CHECK;
PRECONDITION(CheckPointer(pAssembly));
- PRECONDITION(CheckPointer(file));
- PRECONDITION(!IsNilToken(moduleRef) || file->IsAssembly());
+ PRECONDITION(CheckPointer(pPEAssembly));
POSTCONDITION(CheckPointer(RETVAL));
- POSTCONDITION(RETVAL->GetFile() == file);
+ POSTCONDITION(RETVAL->GetPEAssembly() == pPEAssembly);
}
CONTRACT_END;
@@ -764,19 +754,19 @@ Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEFile *file, Allo
// Create the module
#ifdef EnC_SUPPORTED
- if (IsEditAndContinueCapable(pAssembly, file))
+ if (IsEditAndContinueCapable(pAssembly, pPEAssembly))
{
// if file is EnCCapable, always create an EnC-module, but EnC won't necessarily be enabled.
// Debugger enables this by calling SetJITCompilerFlags on LoadModule callback.
void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(EditAndContinueModule))));
- pModule = new (pMemory) EditAndContinueModule(pAssembly, moduleRef, file);
+ pModule = new (pMemory) EditAndContinueModule(pAssembly, moduleRef, pPEAssembly);
}
else
#endif // EnC_SUPPORTED
{
void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(Module))));
- pModule = new (pMemory) Module(pAssembly, moduleRef, file);
+ pModule = new (pMemory) Module(pAssembly, moduleRef, pPEAssembly);
}
PREFIX_ASSUME(pModule != NULL);
@@ -802,10 +792,7 @@ void Module::ApplyMetaData()
ULONG ulCount;
#if defined(PROFILING_SUPPORTED) || defined(EnC_SUPPORTED)
- if (!IsResource())
- {
- UpdateNewlyAddedTypes();
- }
+ UpdateNewlyAddedTypes();
#endif // PROFILING_SUPPORTED || EnC_SUPPORTED
// Ensure for TypeRef
@@ -953,7 +940,7 @@ void Module::Destruct()
delete m_debuggerSpecificData.m_pILOffsetMappingTable;
}
- m_file->Release();
+ m_pPEAssembly->Release();
// If this module was loaded as domain-specific, then
// we must free its ModuleIndex so that it can be reused
@@ -972,7 +959,7 @@ bool Module::NeedsGlobalMethodTable()
CONTRACTL_END;
IMDInternalImport * pImport = GetMDImport();
- if (!IsResource() && pImport->IsValidToken(COR_GLOBAL_PARENT_TOKEN))
+ if (pImport->IsValidToken(COR_GLOBAL_PARENT_TOKEN))
{
{
HENUMInternalHolder funcEnum(pImport);
@@ -1032,7 +1019,7 @@ MethodTable *Module::GetGlobalMethodTable()
#endif // !DACCESS_COMPILE
/*static*/
-BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file)
+BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEAssembly *pPEAssembly)
{
CONTRACTL
{
@@ -1043,13 +1030,12 @@ BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file)
}
CONTRACTL_END;
- _ASSERTE(pAssembly != NULL && file != NULL);
+ _ASSERTE(pAssembly != NULL && pPEAssembly != NULL);
// Some modules are never EnC-capable
return ! (pAssembly->GetDebuggerInfoBits() & DACF_ALLOW_JIT_OPTS ||
- file->IsSystem() ||
- file->IsResource() ||
- file->IsDynamic());
+ pPEAssembly->IsSystem() ||
+ pPEAssembly->IsDynamic());
}
BOOL Module::IsManifest()
@@ -1975,17 +1961,6 @@ void Module::AllocateStatics(AllocMemTracker *pamTracker)
{
STANDARD_VM_CONTRACT;
- if (IsResource())
- {
- m_dwRegularStaticsBlockSize = DomainLocalModule::OffsetOfDataBlob();
- m_dwThreadStaticsBlockSize = ThreadLocalModule::OffsetOfDataBlob();
-
- // If it has no code, we don't have to allocate anything
- LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Resource module %s. No statics needed\n", GetSimpleName()));
- _ASSERTE(m_maxTypeRidStaticsAllocated == 0);
- return;
- }
-
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName()));
// Build the offset table, which will tell us what the offsets for the statics of each class are (one offset for gc handles, one offset
@@ -2114,9 +2089,6 @@ void Module::AllocateMaps()
PTR_TADDR pTable = NULL;
- if (IsResource())
- return;
-
if (IsReflection())
{
// For dynamic modules, it is essential that we at least have a TypeDefToMethodTable
@@ -2402,7 +2374,7 @@ BOOL Module::IsInSameVersionBubble(Module *target)
{
// Check if the current module's image has native manifest metadata, otherwise the current->GetNativeAssemblyImport() asserts.
COUNT_T cMeta=0;
- const void* pMeta = GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta);
+ const void* pMeta = GetPEAssembly()->GetPEImage()->GetNativeManifestMetadata(&cMeta);
if (pMeta == NULL)
{
return FALSE;
@@ -2529,10 +2501,6 @@ ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
}
CONTRACT_END;
- // No symbols for resource modules
- if (IsResource())
- RETURN NULL;
-
if (g_fEEShutDown)
RETURN NULL;
@@ -2565,16 +2533,15 @@ ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
// There are 4 main cases here:
// 1. Assembly is on disk and we'll get the symbols from a file next to the assembly
- // 2. Assembly is provided by the host and we'll get the symbols from the host
- // 3. Assembly was loaded in-memory (by byte array or ref-emit), and symbols were
+ // 2. Assembly was loaded in-memory (by byte array or ref-emit), and symbols were
// provided along with it.
- // 4. Assembly was loaded in-memory but no symbols were provided.
+ // 3. Assembly was loaded in-memory but no symbols were provided.
- // Determine whether we should be looking in memory for the symbols (cases 2 & 3)
- bool fInMemorySymbols = ( m_file->IsIStream() || GetInMemorySymbolStream() );
- if( !fInMemorySymbols && m_file->GetPath().IsEmpty() )
+ // Determine whether we should be looking in memory for the symbols (case 2)
+ bool fInMemorySymbols = GetInMemorySymbolStream();
+ if( !fInMemorySymbols && m_pPEAssembly->GetPath().IsEmpty() )
{
- // Case 4. We don't have a module path, an IStream or an in memory symbol stream,
+ // Case 3. We don't have a module path or an in memory symbol stream,
// so there is no-where to try and get symbols from.
RETURN (NULL);
}
@@ -2657,7 +2624,7 @@ ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
else
{
// The assembly is on disk, so try and load symbols based on the path to the assembly (case 1)
- const SString &path = m_file->GetPath();
+ const SString &path = m_pPEAssembly->GetPath();
// Call Fusion to ensure that any PDB's are shadow copied before
// trying to get a symbol reader. This has to be done once per
@@ -2856,7 +2823,6 @@ void Module::AddClass(mdTypeDef classdef)
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
- PRECONDITION(!IsResource());
}
CONTRACTL_END;
@@ -2913,8 +2879,8 @@ void Module::BuildClassForModule()
// Returns true iff the debugger should be notified about this module
//
// Notes:
-// Debugger doesn't need to be notified about modules that can't be executed,
-// like inspection and resource only. These are just pure data.
+// Debugger doesn't need to be notified about modules that can't be executed.
+// (we do not have such cases at the moment)
//
// This should be immutable for an instance of a module. That ensures that the debugger gets consistent
// notifications about it. It this value mutates, than the debugger may miss relevant notifications.
@@ -2923,11 +2889,6 @@ BOOL Module::IsVisibleToDebugger()
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- if (IsResource())
- {
- return FALSE;
- }
-
return TRUE;
}
@@ -2987,7 +2948,7 @@ TADDR Module::GetIL(DWORD target)
if (target == 0)
return NULL;
- return m_file->GetIL(target);
+ return m_pPEAssembly->GetIL(target);
}
PTR_VOID Module::GetRvaField(DWORD rva)
@@ -2995,7 +2956,7 @@ PTR_VOID Module::GetRvaField(DWORD rva)
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- return m_file->GetRvaField(rva);
+ return m_pPEAssembly->GetRvaField(rva);
}
#ifndef DACCESS_COMPILE
@@ -3004,7 +2965,7 @@ CHECK Module::CheckRvaField(RVA field)
{
WRAPPER_NO_CONTRACT;
if (!IsReflection())
- CHECK(m_file->CheckRvaField(field));
+ CHECK(m_pPEAssembly->CheckRvaField(field));
CHECK_OK;
}
@@ -3018,7 +2979,7 @@ CHECK Module::CheckRvaField(RVA field, COUNT_T size)
CONTRACTL_END;
if (!IsReflection())
- CHECK(m_file->CheckRvaField(field, size));
+ CHECK(m_pPEAssembly->CheckRvaField(field, size));
CHECK_OK;
}
@@ -3028,28 +2989,28 @@ BOOL Module::HasTls()
{
WRAPPER_NO_CONTRACT;
- return m_file->HasTls();
+ return m_pPEAssembly->HasTls();
}
BOOL Module::IsRvaFieldTls(DWORD rva)
{
WRAPPER_NO_CONTRACT;
- return m_file->IsRvaFieldTls(rva);
+ return m_pPEAssembly->IsRvaFieldTls(rva);
}
UINT32 Module::GetFieldTlsOffset(DWORD rva)
{
WRAPPER_NO_CONTRACT;
- return m_file->GetFieldTlsOffset(rva);
+ return m_pPEAssembly->GetFieldTlsOffset(rva);
}
UINT32 Module::GetTlsIndex()
{
WRAPPER_NO_CONTRACT;
- return m_file->GetTlsIndex();
+ return m_pPEAssembly->GetTlsIndex();
}
@@ -3077,7 +3038,7 @@ BOOL Module::IsSigInIL(PCCOR_SIGNATURE signature)
}
CONTRACTL_END;
- return m_file->IsPtrInILImage(signature);
+ return m_pPEAssembly->IsPtrInPEImage(signature);
}
void Module::InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb)
@@ -3182,7 +3143,7 @@ mdToken Module::GetEntryPointToken()
{
WRAPPER_NO_CONTRACT;
- return m_file->GetEntryPointToken();
+ return m_pPEAssembly->GetEntryPointToken();
}
BYTE *Module::GetProfilerBase()
@@ -3195,13 +3156,13 @@ BYTE *Module::GetProfilerBase()
}
CONTRACT_END;
- if (m_file == NULL) // I'd rather assert this is not the case...
+ if (m_pPEAssembly == NULL) // I'd rather assert this is not the case...
{
RETURN NULL;
}
- else if (m_file->IsLoaded())
+ else if (m_pPEAssembly->HasLoadedPEImage())
{
- RETURN (BYTE*)(m_file->GetLoadedIL()->GetBase());
+ RETURN (BYTE*)(m_pPEAssembly->GetLoadedLayout()->GetBase());
}
else
{
@@ -3413,20 +3374,18 @@ DomainAssembly * Module::LoadAssembly(mdAssemblyRef kAssemblyRef)
}
{
- PEAssemblyHolder pFile = GetDomainAssembly()->GetFile()->LoadAssembly(
- kAssemblyRef,
- NULL);
+ PEAssemblyHolder pPEAssembly = GetDomainAssembly()->GetPEAssembly()->LoadAssembly(kAssemblyRef);
AssemblySpec spec;
spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainAssembly());
// Set the binding context in the AssemblySpec if one is available. This can happen if the LoadAssembly ended up
// invoking the custom AssemblyLoadContext implementation that returned a reference to an assembly bound to a different
// AssemblyLoadContext implementation.
- AssemblyBinder *pBinder = pFile->GetAssemblyBinder();
+ AssemblyBinder *pBinder = pPEAssembly->GetAssemblyBinder();
if (pBinder != NULL)
{
spec.SetBinder(pBinder);
}
- pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pFile, FILE_LOADED);
+ pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED);
}
if (pDomainAssembly != NULL)
@@ -3434,7 +3393,7 @@ DomainAssembly * Module::LoadAssembly(mdAssemblyRef kAssemblyRef)
_ASSERTE(
pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find CoreLib (see AppDomain::FindCachedFile)
!pDomainAssembly->IsLoaded() || // GetAssemblyIfLoaded will not find not-yet-loaded assemblies
- GetAssemblyIfLoaded(kAssemblyRef, NULL, FALSE, pDomainAssembly->GetFile()->GetHostAssembly()->GetBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
+ GetAssemblyIfLoaded(kAssemblyRef, NULL, FALSE, pDomainAssembly->GetPEAssembly()->GetHostAssembly()->GetBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
if (pDomainAssembly->GetCurrentAssembly() != NULL)
{
@@ -3447,7 +3406,7 @@ DomainAssembly * Module::LoadAssembly(mdAssemblyRef kAssemblyRef)
#endif // !DACCESS_COMPILE
-Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL permitResources)
+Module *Module::GetModuleIfLoaded(mdFile kFile)
{
CONTRACT(Module *)
{
@@ -3479,7 +3438,7 @@ Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL
if (kFile == mdTokenNil)
RETURN NULL;
- RETURN GetAssembly()->GetManifestModule()->GetModuleIfLoaded(kFile, onlyLoadedInAppDomain, permitResources);
+ RETURN GetAssembly()->GetManifestModule()->GetModuleIfLoaded(kFile);
}
Module *pModule = LookupFile(kFile);
@@ -3519,10 +3478,6 @@ Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL
#endif
}
- // We may not want to return a resource module
- if (!permitResources && pModule && pModule->IsResource())
- pModule = NULL;
-
#ifndef DACCESS_COMPILE
#endif // !DACCESS_COMPILE
RETURN pModule;
@@ -3530,8 +3485,7 @@ Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL
#ifndef DACCESS_COMPILE
-DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile,
- BOOL permitResources/*=TRUE*/, BOOL bindOnly/*=FALSE*/)
+DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile)
{
CONTRACT(DomainFile *)
{
@@ -3541,38 +3495,32 @@ DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile,
MODE_ANY;
PRECONDITION(TypeFromToken(kFile) == mdtFile
|| TypeFromToken(kFile) == mdtModuleRef);
- POSTCONDITION(CheckPointer(RETVAL, !permitResources || bindOnly ? NULL_OK : NULL_NOT_OK));
}
CONTRACT_END;
- if (bindOnly)
+ LPCSTR psModuleName=NULL;
+ if (TypeFromToken(kFile) == mdtModuleRef)
{
- RETURN NULL;
+ // This is a moduleRef
+ IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &psModuleName));
}
else
{
- LPCSTR psModuleName=NULL;
- if (TypeFromToken(kFile) == mdtModuleRef)
- {
- // This is a moduleRef
- IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &psModuleName));
- }
- else
- {
- // This is mdtFile
- IfFailThrow(GetAssembly()->GetManifestImport()->GetFileProps(kFile,
- &psModuleName,
- NULL,
- NULL,
- NULL));
- }
- SString name(SString::Utf8, psModuleName);
- EEFileLoadException::Throw(name, COR_E_MULTIMODULEASSEMBLIESDIALLOWED, NULL);
+ // This is mdtFile
+ IfFailThrow(GetAssembly()->GetManifestImport()->GetFileProps(kFile,
+ &psModuleName,
+ NULL,
+ NULL,
+ NULL));
}
+
+ SString name(SString::Utf8, psModuleName);
+ EEFileLoadException::Throw(name, COR_E_MULTIMODULEASSEMBLIESDIALLOWED, NULL);
+ RETURN NULL;
}
#endif // !DACCESS_COMPILE
-PTR_Module Module::LookupModule(mdToken kFile,BOOL permitResources/*=TRUE*/)
+PTR_Module Module::LookupModule(mdToken kFile)
{
CONTRACT(PTR_Module)
{
@@ -3598,7 +3546,7 @@ PTR_Module Module::LookupModule(mdToken kFile,BOOL permitResources/*=TRUE*/)
if (kFileLocal == mdTokenNil)
COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- RETURN GetAssembly()->GetManifestModule()->LookupModule(kFileLocal, permitResources);
+ RETURN GetAssembly()->GetManifestModule()->LookupModule(kFileLocal);
}
PTR_Module pModule = LookupFile(kFile);
@@ -4111,8 +4059,8 @@ BOOL Module::NotifyDebuggerLoad(AppDomain *pDomain, DomainFile * pDomainFile, in
if (flags & ATTACH_MODULE_LOAD)
{
g_pDebugInterface->LoadModule(this,
- m_file->GetPath(),
- m_file->GetPath().GetCount(),
+ m_pPEAssembly->GetPath(),
+ m_pPEAssembly->GetPath().GetCount(),
GetAssembly(),
pDomain,
pDomainFile,
@@ -4168,9 +4116,9 @@ using GetTokenForVTableEntry_t = mdToken(STDMETHODCALLTYPE*)(HMODULE module, BYT
static HMODULE GetIJWHostForModule(Module* module)
{
#if !defined(TARGET_UNIX)
- PEDecoder* pe = module->GetFile()->GetLoadedIL();
+ PEDecoder* pe = module->GetPEAssembly()->GetLoadedLayout();
- BYTE* baseAddress = (BYTE*)module->GetFile()->GetIJWBase();
+ BYTE* baseAddress = (BYTE*)module->GetPEAssembly()->GetIJWBase();
IMAGE_IMPORT_DESCRIPTOR* importDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)pe->GetDirectoryData(pe->GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
@@ -4286,7 +4234,7 @@ void Module::FixupVTables()
// If we've already fixed up, or this is not an IJW module, just return.
// NOTE: This relies on ILOnly files not having fixups. If this changes,
// we need to change this conditional.
- if (IsIJWFixedUp() || m_file->IsILOnly()) {
+ if (IsIJWFixedUp() || m_pPEAssembly->IsILOnly()) {
return;
}
@@ -4302,11 +4250,11 @@ void Module::FixupVTables()
GetTokenForVTableEntryCallback = GetTokenForVTableEntry;
}
- HINSTANCE hInstThis = GetFile()->GetIJWBase();
+ HINSTANCE hInstThis = GetPEAssembly()->GetIJWBase();
// Get vtable fixup data
COUNT_T cFixupRecords;
- IMAGE_COR_VTABLEFIXUP *pFixupTable = m_file->GetVTableFixups(&cFixupRecords);
+ IMAGE_COR_VTABLEFIXUP *pFixupTable = m_pPEAssembly->GetVTableFixups(&cFixupRecords);
// No records then return
if (cFixupRecords == 0) {
@@ -4314,7 +4262,7 @@ void Module::FixupVTables()
}
// Now, we need to take a lock to serialize fixup.
- PEImage::IJWFixupData *pData = PEImage::GetIJWData(m_file->GetIJWBase());
+ PEImage::IJWFixupData *pData = PEImage::GetIJWData(m_pPEAssembly->GetIJWBase());
// If it's already been fixed (in some other appdomain), record the fact and return
if (pData->IsFixedUp()) {
@@ -4381,7 +4329,7 @@ void Module::FixupVTables()
(pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED)) ||
(pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN)))
{
- const BYTE** pPointers = (const BYTE **)m_file->GetVTable(pFixupTable[iFixup].RVA);
+ const BYTE** pPointers = (const BYTE **)m_pPEAssembly->GetVTable(pFixupTable[iFixup].RVA);
for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
{
if (pData->IsMethodFixedUp(iFixup, iMethod))
@@ -4465,7 +4413,7 @@ void Module::FixupVTables()
continue;
const BYTE** pPointers = (const BYTE **)
- m_file->GetVTable(pFixupTable[iFixup].RVA);
+ m_pPEAssembly->GetVTable(pFixupTable[iFixup].RVA);
// Vtables can be 32 or 64 bit.
if (pFixupTable[iFixup].Type == COR_VTABLE_PTRSIZED)
@@ -4556,7 +4504,7 @@ LoaderHeap *Module::GetDllThunkHeap()
MODE_ANY;
}
CONTRACTL_END;
- return PEImage::GetDllThunkHeap(GetFile()->GetIJWBase());
+ return PEImage::GetDllThunkHeap(GetPEAssembly()->GetIJWBase());
}
@@ -4661,7 +4609,7 @@ IMDInternalImport* Module::GetNativeAssemblyImport(BOOL loadAllowed)
}
CONTRACT_END;
- RETURN GetFile()->GetOpenedILimage()->GetNativeMDImport(loadAllowed);
+ RETURN GetPEAssembly()->GetPEImage()->GetNativeMDImport(loadAllowed);
}
BYTE* Module::GetNativeFixupBlobData(RVA rva)
@@ -4930,7 +4878,7 @@ HANDLE Module::OpenMethodProfileDataLogFile(GUID mvid)
HANDLE profileDataFile = INVALID_HANDLE_VALUE;
SString path;
- LPCWSTR assemblyPath = m_file->GetPath();
+ LPCWSTR assemblyPath = m_pPEAssembly->GetPath();
LPCWSTR ibcDir = g_pConfig->GetZapBBInstrDir(); // should we put the ibc data into a particular directory?
if (ibcDir == 0) {
path.Set(assemblyPath); // no, then put it beside the IL dll
@@ -6402,9 +6350,6 @@ HRESULT Module::WriteMethodProfileDataLogFile(bool cleanup)
HRESULT hr = S_OK;
- if (IsResource())
- return S_OK;
-
EX_TRY
{
if (GetAssembly()->IsInstrumented() && (m_pProfilingBlobTable != NULL) && (m_tokenProfileData != NULL))
@@ -6990,14 +6935,14 @@ idMethodSpec Module::LogInstantiatedMethod(const MethodDesc * md, ULONG flagNum)
// ===========================================================================
/* static */
-ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, AllocMemTracker *pamTracker, LPCWSTR szName)
+ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEAssembly *pPEAssembly, AllocMemTracker *pamTracker, LPCWSTR szName)
{
CONTRACT(ReflectionModule *)
{
STANDARD_VM_CHECK;
PRECONDITION(CheckPointer(pAssembly));
- PRECONDITION(CheckPointer(pFile));
- PRECONDITION(pFile->IsDynamic());
+ PRECONDITION(CheckPointer(pPEAssembly));
+ PRECONDITION(pPEAssembly->IsDynamic());
POSTCONDITION(CheckPointer(RETVAL));
}
CONTRACT_END;
@@ -7005,14 +6950,13 @@ ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, A
// Hoist CONTRACT into separate routine because of EX incompatibility
mdFile token;
- _ASSERTE(pFile->IsAssembly());
token = mdFileNil;
// Initial memory block for Modules must be zero-initialized (to make it harder
// to introduce Destruct crashes arising from OOM's during initialization.)
void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ReflectionModule))));
- ReflectionModuleHolder pModule(new (pMemory) ReflectionModule(pAssembly, token, pFile));
+ ReflectionModuleHolder pModule(new (pMemory) ReflectionModule(pAssembly, token, pPEAssembly));
pModule->DoInit(pamTracker, szName);
@@ -7025,8 +6969,8 @@ ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, A
// The constructor phase initializes just enough so that Destruct() can be safely called.
// It cannot throw or fail.
//
-ReflectionModule::ReflectionModule(Assembly *pAssembly, mdFile token, PEFile *pFile)
- : Module(pAssembly, token, pFile)
+ReflectionModule::ReflectionModule(Assembly *pAssembly, mdFile token, PEAssembly *pPEAssembly)
+ : Module(pAssembly, token, pPEAssembly)
{
CONTRACTL
{
@@ -7569,9 +7513,9 @@ void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
m_ModuleID->EnumMemoryRegions(flags);
}
- if (m_file.IsValid())
+ if (m_pPEAssembly.IsValid())
{
- m_file->EnumMemoryRegions(flags);
+ m_pPEAssembly->EnumMemoryRegions(flags);
}
if (m_pAssembly.IsValid())
{
@@ -7724,11 +7668,11 @@ LPCWSTR Module::GetPathForErrorMessages()
}
CONTRACTL_END
- PEFile *pFile = GetFile();
+ PEAssembly *pPEAssembly = GetPEAssembly();
- if (pFile)
+ if (pPEAssembly)
{
- return pFile->GetPathForErrorMessages();
+ return pPEAssembly->GetPathForErrorMessages();
}
else
{
diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h
index 2e3b474ef298a..e7dd5629a2c84 100644
--- a/src/coreclr/vm/ceeload.h
+++ b/src/coreclr/vm/ceeload.h
@@ -19,7 +19,7 @@
#include "corsym.h"
#include "typehandle.h"
#include "arraylist.h"
-#include "pefile.h"
+#include "peassembly.h"
#include "typehash.h"
#include "contractimpl.h"
#include "bitmask.h"
@@ -43,7 +43,6 @@
#include "ilinstrumentation.h"
-class PELoader;
class Stub;
class MethodDesc;
class FieldDesc;
@@ -736,7 +735,7 @@ struct ThreadLocalModule;
// Native code (NGEN module). A module live in a code:Assembly
//
// Some important fields are
-// * code:Module.m_file - this points at a code:PEFile that understands the layout of a PE file. The most
+// * code:Module.m_pPEAssembly - this points at a code:PEAssembly that understands the layout of a PE assembly. The most
// important part is getting at the code:Module (see file:..\inc\corhdr.h#ManagedHeader) from there
// you can get at the Meta-data and IL)
// * code:Module.m_pAvailableClasses - this is a table that lets you look up the types (the code:EEClass)
@@ -758,7 +757,7 @@ class Module
private:
PTR_CUTF8 m_pSimpleName; // Cached simple name for better performance and easier diagnostics
- PTR_PEFile m_file;
+ PTR_PEAssembly m_pPEAssembly;
enum {
// These are the values set in m_dwTransientFlags.
@@ -1079,10 +1078,10 @@ class Module
#endif // _DEBUG
public:
- static Module *Create(Assembly *pAssembly, mdFile kFile, PEFile *pFile, AllocMemTracker *pamTracker);
+ static Module *Create(Assembly *pAssembly, mdFile kFile, PEAssembly *pPEAssembly, AllocMemTracker *pamTracker);
protected:
- Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file);
+ Module(Assembly *pAssembly, mdFile moduleRef, PEAssembly *file);
public:
@@ -1092,9 +1091,7 @@ class Module
PTR_LoaderAllocator GetLoaderAllocator();
- PTR_PEFile GetFile() const { LIMITED_METHOD_DAC_CONTRACT; return m_file; }
-
- static size_t GetFileOffset() { LIMITED_METHOD_CONTRACT; return offsetof(Module, m_file); }
+ PTR_PEAssembly GetPEAssembly() const { LIMITED_METHOD_DAC_CONTRACT; return m_pPEAssembly; }
BOOL IsManifest();
@@ -1153,10 +1150,8 @@ class Module
return m_moduleRef;
}
- BOOL IsResource() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GetFile()->IsResource(); }
- BOOL IsPEFile() const { WRAPPER_NO_CONTRACT; return !GetFile()->IsDynamic(); }
- BOOL IsReflection() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GetFile()->IsDynamic(); }
- BOOL IsIbcOptimized() const { WRAPPER_NO_CONTRACT; return GetFile()->IsIbcOptimized(); }
+ BOOL IsPEFile() const { WRAPPER_NO_CONTRACT; return !GetPEAssembly()->IsDynamic(); }
+ BOOL IsReflection() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GetPEAssembly()->IsDynamic(); }
// Returns true iff the debugger can see this module.
BOOL IsVisibleToDebugger();
@@ -1170,11 +1165,9 @@ class Module
virtual BOOL IsEditAndContinueCapable() const { return FALSE; }
- BOOL IsIStream() { LIMITED_METHOD_CONTRACT; return GetFile()->IsIStream(); }
-
- BOOL IsSystem() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return m_file->IsSystem(); }
+ BOOL IsSystem() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return m_pPEAssembly->IsSystem(); }
- static BOOL IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file);
+ static BOOL IsEditAndContinueCapable(Assembly *pAssembly, PEAssembly *file);
void EnableEditAndContinue()
{
@@ -1265,7 +1258,7 @@ class Module
return DacGetMDImport(GetReflectionModule(), true);
}
#endif // DACCESS_COMPILE
- return m_file->GetPersistentMDImport();
+ return m_pPEAssembly->GetMDImport();
}
#ifndef DACCESS_COMPILE
@@ -1273,21 +1266,14 @@ class Module
{
WRAPPER_NO_CONTRACT;
- return m_file->GetEmitter();
+ return m_pPEAssembly->GetEmitter();
}
IMetaDataImport2 *GetRWImporter()
{
WRAPPER_NO_CONTRACT;
- return m_file->GetRWImporter();
- }
-
- IMetaDataAssemblyImport *GetAssemblyImporter()
- {
- WRAPPER_NO_CONTRACT;
-
- return m_file->GetAssemblyImporter();
+ return m_pPEAssembly->GetRWImporter();
}
HRESULT GetReadablePublicMetaDataInterface(DWORD dwOpenFlags, REFIID riid, LPVOID * ppvInterface);
@@ -1379,54 +1365,26 @@ class Module
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
-
- _ASSERTE(!IsResource());
- }
return m_pAvailableClasses;
}
#ifndef DACCESS_COMPILE
void SetAvailableClassHash(EEClassHashTable *pAvailableClasses)
{
- LIMITED_METHOD_CONTRACT;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
- _ASSERTE(!IsResource());
- }
m_pAvailableClasses = pAvailableClasses;
}
#endif // !DACCESS_COMPILE
PTR_EEClassHashTable GetAvailableClassCaseInsHash()
{
LIMITED_METHOD_CONTRACT;
- SUPPORTS_DAC;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
- _ASSERTE(!IsResource());
- }
return m_pAvailableClassesCaseIns;
}
#ifndef DACCESS_COMPILE
void SetAvailableClassCaseInsHash(EEClassHashTable *pAvailableClassesCaseIns)
{
- LIMITED_METHOD_CONTRACT;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
- _ASSERTE(!IsResource());
- }
m_pAvailableClassesCaseIns = pAvailableClassesCaseIns;
}
#endif // !DACCESS_COMPILE
@@ -1436,26 +1394,14 @@ class Module
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
- _ASSERTE(!IsResource());
- }
return m_pAvailableParamTypes;
}
InstMethodHashTable *GetInstMethodHashTable()
{
LIMITED_METHOD_CONTRACT;
- {
- // IsResource() may lock when accessing metadata, but this is only in debug,
- // for the assert below
- CONTRACT_VIOLATION(TakesLockViolation);
- _ASSERTE(!IsResource());
- }
return m_pInstMethodHashTable;
}
@@ -1484,9 +1430,9 @@ class Module
public:
DomainAssembly * LoadAssembly(mdAssemblyRef kAssemblyRef);
- Module *GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL loadAllowed);
- DomainFile *LoadModule(AppDomain *pDomain, mdFile kFile, BOOL loadResources = TRUE, BOOL bindOnly = FALSE);
- PTR_Module LookupModule(mdToken kFile, BOOL loadResources = TRUE); //wrapper over GetModuleIfLoaded, takes modulerefs as well
+ Module *GetModuleIfLoaded(mdFile kFile);
+ DomainFile *LoadModule(AppDomain *pDomain, mdFile kFile);
+ PTR_Module LookupModule(mdToken kFile); //wrapper over GetModuleIfLoaded, takes modulerefs as well
DWORD GetAssemblyRefFlags(mdAssemblyRef tkAssemblyRef);
// RID maps
@@ -1806,8 +1752,8 @@ class Module
public:
#ifndef DACCESS_COMPILE
- BOOL Equals(Module *pModule) { WRAPPER_NO_CONTRACT; return m_file->Equals(pModule->m_file); }
- BOOL Equals(PEFile *pFile) { WRAPPER_NO_CONTRACT; return m_file->Equals(pFile); }
+ BOOL Equals(Module *pModule) { WRAPPER_NO_CONTRACT; return m_pPEAssembly->Equals(pModule->m_pPEAssembly); }
+ BOOL Equals(PEAssembly *pPEAssembly) { WRAPPER_NO_CONTRACT; return m_pPEAssembly->Equals(pPEAssembly); }
#endif // !DACCESS_COMPILE
LPCUTF8 GetSimpleName()
@@ -1817,11 +1763,11 @@ class Module
return m_pSimpleName;
}
- HRESULT GetScopeName(LPCUTF8 * pszName) { WRAPPER_NO_CONTRACT; return m_file->GetScopeName(pszName); }
- const SString &GetPath() { WRAPPER_NO_CONTRACT; return m_file->GetPath(); }
+ HRESULT GetScopeName(LPCUTF8 * pszName) { WRAPPER_NO_CONTRACT; return m_pPEAssembly->GetScopeName(pszName); }
+ const SString &GetPath() { WRAPPER_NO_CONTRACT; return m_pPEAssembly->GetPath(); }
#ifdef LOGGING
- LPCWSTR GetDebugName() { WRAPPER_NO_CONTRACT; return m_file->GetDebugName(); }
+ LPCWSTR GetDebugName() { WRAPPER_NO_CONTRACT; return m_pPEAssembly->GetDebugName(); }
#endif
PEImageLayout * GetReadyToRunImage();
@@ -1837,7 +1783,7 @@ class Module
CHECK CheckRvaField(RVA field, COUNT_T size);
const void *GetInternalPInvokeTarget(RVA target)
- { WRAPPER_NO_CONTRACT; return m_file->GetInternalPInvokeTarget(target); }
+ { WRAPPER_NO_CONTRACT; return m_pPEAssembly->GetInternalPInvokeTarget(target); }
BOOL HasTls();
BOOL IsRvaFieldTls(DWORD field);
@@ -2268,7 +2214,7 @@ class ReflectionModule : public Module
bool m_fSuppressMetadataCapture;
#if !defined DACCESS_COMPILE
- ReflectionModule(Assembly *pAssembly, mdFile token, PEFile *pFile);
+ ReflectionModule(Assembly *pAssembly, mdFile token, PEAssembly *pPEAssembly);
#endif // !DACCESS_COMPILE
public:
@@ -2279,7 +2225,7 @@ class ReflectionModule : public Module
#endif
#if !defined DACCESS_COMPILE
- static ReflectionModule *Create(Assembly *pAssembly, PEFile *pFile, AllocMemTracker *pamTracker, LPCWSTR szName);
+ static ReflectionModule *Create(Assembly *pAssembly, PEAssembly *pPEAssembly, AllocMemTracker *pamTracker, LPCWSTR szName);
void Initialize(AllocMemTracker *pamTracker, LPCWSTR szName);
void Destruct();
#endif // !DACCESS_COMPILE
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 9c68686b31d6e..8f347255d4e0d 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -848,7 +848,6 @@ void EEStartupHelper()
// Setup the domains. Threads are started in a default domain.
// Static initialization
- PEAssembly::Attach();
BaseDomain::Attach();
SystemDomain::Attach();
diff --git a/src/coreclr/vm/clrex.cpp b/src/coreclr/vm/clrex.cpp
index b4959ad479237..a1fe3e4c8985d 100644
--- a/src/coreclr/vm/clrex.cpp
+++ b/src/coreclr/vm/clrex.cpp
@@ -1733,7 +1733,7 @@ void DECLSPEC_NORETURN EEFileLoadException::Throw(AssemblySpec *pSpec, HRESULT
}
/* static */
-void DECLSPEC_NORETURN EEFileLoadException::Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException /* = NULL*/)
+void DECLSPEC_NORETURN EEFileLoadException::Throw(PEAssembly *pPEAssembly, HRESULT hr, Exception *pInnerException /* = NULL*/)
{
CONTRACTL
{
@@ -1749,11 +1749,8 @@ void DECLSPEC_NORETURN EEFileLoadException::Throw(PEFile *pFile, HRESULT hr, Exc
COMPlusThrowOM();
StackSString name;
+ pPEAssembly->GetDisplayName(name);
- if (pFile->IsAssembly())
- ((PEAssembly*)pFile)->GetDisplayName(name);
- else
- name = StackSString(SString::Utf8, pFile->GetSimpleName());
EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
}
diff --git a/src/coreclr/vm/clrex.h b/src/coreclr/vm/clrex.h
index 569e8442854cd..cf7d458f90ff3 100644
--- a/src/coreclr/vm/clrex.h
+++ b/src/coreclr/vm/clrex.h
@@ -18,7 +18,6 @@
class BaseBind;
class AssemblySpec;
-class PEFile;
class PEAssembly;
enum StackTraceElementFlags
@@ -678,7 +677,7 @@ class EEFileLoadException : public EEException
static RuntimeExceptionKind GetFileLoadKind(HRESULT hr);
static void DECLSPEC_NORETURN Throw(AssemblySpec *pSpec, HRESULT hr, Exception *pInnerException = NULL);
- static void DECLSPEC_NORETURN Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException = NULL);
+ static void DECLSPEC_NORETURN Throw(PEAssembly *pPEAssembly, HRESULT hr, Exception *pInnerException = NULL);
static void DECLSPEC_NORETURN Throw(LPCWSTR path, HRESULT hr, Exception *pInnerException = NULL);
static void DECLSPEC_NORETURN Throw(PEAssembly *parent, const void *memory, COUNT_T size, HRESULT hr, Exception *pInnerException = NULL);
static BOOL CheckType(Exception* ex); // typeof(EEFileLoadException)
diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp
index 8b53e019d39aa..9392f6c11d93e 100644
--- a/src/coreclr/vm/clsload.cpp
+++ b/src/coreclr/vm/clsload.cpp
@@ -654,8 +654,6 @@ void ClassLoader::GetClassValue(NameHandleTable nhTable,
Module * pCurrentClsModule = i.GetModule();
PREFIX_ASSUME(pCurrentClsModule != NULL);
- if (pCurrentClsModule->IsResource())
- continue;
if (pLookInThisModuleOnly && (pCurrentClsModule != pLookInThisModuleOnly))
continue;
@@ -844,7 +842,7 @@ void ClassLoader::LazyPopulateCaseSensitiveHashTables()
{
Module *pModule = i.GetModule();
PREFIX_ASSUME(pModule != NULL);
- if (pModule->IsResource() || pModule->GetAvailableClassHash() != NULL)
+ if (pModule->GetAvailableClassHash() != NULL)
continue;
// Lazy construction of the case-sensitive hashtable of types is *only* a scenario for ReadyToRun images
@@ -858,16 +856,13 @@ void ClassLoader::LazyPopulateCaseSensitiveHashTables()
}
// Add exported types of the manifest module to the hashtable
- if (!GetAssembly()->GetManifestModule()->IsResource())
- {
- IMDInternalImport * pManifestImport = GetAssembly()->GetManifestImport();
- HENUMInternalHolder phEnum(pManifestImport);
- phEnum.EnumInit(mdtExportedType, mdTokenNil);
+ IMDInternalImport * pManifestImport = GetAssembly()->GetManifestImport();
+ HENUMInternalHolder phEnum(pManifestImport);
+ phEnum.EnumInit(mdtExportedType, mdTokenNil);
- mdToken mdExportedType;
- while (pManifestImport->EnumNext(&phEnum, &mdExportedType))
- AddExportedTypeHaveLock(GetAssembly()->GetManifestModule(), mdExportedType, &amTracker);
- }
+ mdToken mdExportedType;
+ while (pManifestImport->EnumNext(&phEnum, &mdExportedType))
+ AddExportedTypeHaveLock(GetAssembly()->GetManifestModule(), mdExportedType, &amTracker);
amTracker.SuppressRelease();
}
@@ -884,7 +879,7 @@ void ClassLoader::LazyPopulateCaseInsensitiveHashTables()
}
CONTRACTL_END;
- if (!GetAssembly()->GetManifestModule()->IsResource() && GetAssembly()->GetManifestModule()->GetAvailableClassHash() == NULL)
+ if (GetAssembly()->GetManifestModule()->GetAvailableClassHash() == NULL)
{
// This is a R2R assembly, and a case insensitive type lookup was triggered.
// Construct the case-sensitive table first, since the case-insensitive table
@@ -900,9 +895,6 @@ void ClassLoader::LazyPopulateCaseInsensitiveHashTables()
while (i.Next())
{
Module *pModule = i.GetModule();
- if (pModule->IsResource())
- continue;
-
if (pModule->GetAvailableClassCaseInsHash() == NULL)
{
EEClassHashTable *pNewClassCaseInsHash = pModule->GetAvailableClassHash()->MakeCaseInsensitiveTable(pModule, &amTracker);
diff --git a/src/coreclr/vm/commodule.cpp b/src/coreclr/vm/commodule.cpp
index 99b4982329f04..c00a08336a7c2 100644
--- a/src/coreclr/vm/commodule.cpp
+++ b/src/coreclr/vm/commodule.cpp
@@ -651,26 +651,13 @@ void QCALLTYPE COMModule::GetScopeName(QCall::ModuleHandle pModule, QCall::Strin
BEGIN_QCALL;
- LPCSTR szName = NULL;
-
- if (pModule->IsResource())
- {
- IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetFileProps(
- pModule->GetModuleRef(),
- &szName,
- NULL,
- NULL,
- NULL));
- }
- else
+ if (!pModule->GetMDImport()->IsValidToken(pModule->GetMDImport()->GetModuleFromScope()))
{
- if (!pModule->GetMDImport()->IsValidToken(pModule->GetMDImport()->GetModuleFromScope()))
- {
- ThrowHR(COR_E_BADIMAGEFORMAT);
- }
- IfFailThrow(pModule->GetMDImport()->GetScopeProps(&szName, 0));
+ ThrowHR(COR_E_BADIMAGEFORMAT);
}
+ LPCSTR szName = NULL;
+ IfFailThrow(pModule->GetMDImport()->GetScopeProps(&szName, 0));
retString.Set(szName);
END_QCALL;
@@ -734,10 +721,10 @@ HINSTANCE QCALLTYPE COMModule::GetHINSTANCE(QCall::ModuleHandle pModule)
// This returns the base address
// Other modules should have zero base
- PEFile *pPEFile = pModule->GetFile();
- if (!pPEFile->IsDynamic() && !pPEFile->IsResource())
+ PEAssembly *pPEAssembly = pModule->GetPEAssembly();
+ if (!pPEAssembly->IsDynamic())
{
- hMod = (HMODULE) pModule->GetFile()->GetManagedFileContents();
+ hMod = (HMODULE) pModule->GetPEAssembly()->GetManagedFileContents();
}
//If we don't have an hMod, set it to -1 so that they know that there's none
@@ -801,12 +788,6 @@ Object* GetTypesInner(Module* pModule)
int AllocSize = 0;
MethodTable* pMT = NULL;
- if (pModule->IsResource())
- {
- refArrClasses = (PTRARRAYREF) AllocateObjectArray(0, CoreLibBinder::GetClass(CLASS__CLASS));
- RETURN(OBJECTREFToObject(refArrClasses));
- }
-
GCPROTECT_BEGIN(refArrClasses);
GCPROTECT_BEGIN(xcept);
@@ -890,15 +871,3 @@ Object* GetTypesInner(Module* pModule)
RETURN(OBJECTREFToObject(refArrClasses));
}
-
-
-FCIMPL1(FC_BOOL_RET, COMModule::IsResource, ReflectModuleBaseObject* pModuleUNSAFE)
-{
- FCALL_CONTRACT;
-
- if (pModuleUNSAFE == NULL)
- FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
-
- FC_RETURN_BOOL(pModuleUNSAFE->GetModule()->IsResource());
-}
-FCIMPLEND
diff --git a/src/coreclr/vm/commodule.h b/src/coreclr/vm/commodule.h
index c995ec80dfd82..4453214c473a5 100644
--- a/src/coreclr/vm/commodule.h
+++ b/src/coreclr/vm/commodule.h
@@ -90,8 +90,6 @@ class COMModule
static
void QCALLTYPE SetModuleName(QCall::ModuleHandle pModule, LPCWSTR wszModuleName);
- static FCDECL1(FC_BOOL_RET, IsResource, ReflectModuleBaseObject* pModuleUNSAFE);
-
static FCDECL1(Object*, GetMethods, ReflectModuleBaseObject* refThisUNSAFE);
static
diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h
index 7d2f3532219a3..bcd9af84555c6 100644
--- a/src/coreclr/vm/common.h
+++ b/src/coreclr/vm/common.h
@@ -345,7 +345,7 @@ inline void ClrRestoreNonvolatileContext(PCONTEXT ContextRecord)
#include "specialstatics.h"
#include "object.h" // We should not really need to put this so early...
#include "gchelpers.h"
-#include "pefile.h"
+#include "peassembly.h"
#include "clrex.h"
#include "clsload.hpp" // We should not really need to put this so early...
#include "siginfo.hpp"
@@ -362,7 +362,7 @@ inline void ClrRestoreNonvolatileContext(PCONTEXT ContextRecord)
#include "appdomain.hpp"
#include "appdomain.inl"
#include "assembly.hpp"
-#include "pefile.inl"
+#include "peassembly.inl"
#include "excep.h"
#include "method.hpp"
#include "field.h"
diff --git a/src/coreclr/vm/coreassemblyspec.cpp b/src/coreclr/vm/coreassemblyspec.cpp
index 9d1547cda8edd..eaaddafdbe9c6 100644
--- a/src/coreclr/vm/coreassemblyspec.cpp
+++ b/src/coreclr/vm/coreassemblyspec.cpp
@@ -116,7 +116,7 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
{
PEImageHolder pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default, bundleFileLocation);
- // Make sure that the IL image can be opened if the native image is not available.
+ // Make sure that the IL image can be opened.
hr=pImage->TryOpenFile();
if (FAILED(hr))
{
@@ -144,7 +144,7 @@ STDAPI BinderAcquireImport(PEImage *pPEImage,
EX_TRY
{
- PEImageLayoutHolder pLayout(pPEImage->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED));
+ PEImageLayout* pLayout = pPEImage->GetOrCreateLayout(PEImageLayout::LAYOUT_ANY);
// CheckCorHeader includes check of NT headers too
if (!pLayout->CheckCorHeader())
diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index a4b2bfa74a876..861ec15be77a8 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -612,8 +612,6 @@ HRESULT CorHost2::CreateAppDomainWithManager(
if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS)
pDomain->SetForceTrivialWaitOperations();
- pDomain->CreateBinderContext();
-
{
GCX_COOP();
diff --git a/src/coreclr/vm/debugdebugger.cpp b/src/coreclr/vm/debugdebugger.cpp
index e21939990405c..e6313d9c20be9 100644
--- a/src/coreclr/vm/debugdebugger.cpp
+++ b/src/coreclr/vm/debugdebugger.cpp
@@ -713,11 +713,11 @@ FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
I4 *pMethodToken = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiMethodToken)->GetDirectPointerToNonObjectElements();
pMethodToken[iNumValidFrames] = pMethod->GetMemberDef();
- PEFile *pPEFile = pModule->GetFile();
+ PEAssembly *pPEAssembly = pModule->GetPEAssembly();
// Get the address and size of the loaded PE image
COUNT_T peSize;
- PTR_CVOID peAddress = pPEFile->GetLoadedImageContents(&peSize);
+ PTR_CVOID peAddress = pPEAssembly->GetLoadedImageContents(&peSize);
// Save the PE address and size
PTR_CVOID *pLoadedPeAddress = (PTR_CVOID *)pStackFrameHelper->rgLoadedPeAddress->GetDataPtr();
@@ -727,11 +727,11 @@ FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
pLoadedPeSize[iNumValidFrames] = (I4)peSize;
// Set flag indicating PE file in memory has the on disk layout
- if (!pPEFile->IsDynamic())
+ if (!pPEAssembly->IsDynamic())
{
// This flag is only available for non-dynamic assemblies.
U1 *pIsFileLayout = (U1 *)((BOOLARRAYREF)pStackFrameHelper->rgiIsFileLayout)->GetDirectPointerToNonObjectElements();
- pIsFileLayout[iNumValidFrames] = (U1) pPEFile->GetLoaded()->IsFlat();
+ pIsFileLayout[iNumValidFrames] = (U1) pPEAssembly->GetLoadedLayout()->IsFlat();
}
// If there is a in memory symbol stream
@@ -750,7 +750,7 @@ FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
else
{
// Set the pdb path (assembly file name)
- SString assemblyPath = pPEFile->GetIdentityPath();
+ SString assemblyPath = pPEAssembly->GetIdentityPath();
if (!assemblyPath.IsEmpty())
{
OBJECTREF obj = (OBJECTREF)StringObject::NewString(assemblyPath);
diff --git a/src/coreclr/vm/domainfile.cpp b/src/coreclr/vm/domainfile.cpp
index 70f03913f1879..ca9ea6565d3f7 100644
--- a/src/coreclr/vm/domainfile.cpp
+++ b/src/coreclr/vm/domainfile.cpp
@@ -30,10 +30,9 @@
#endif // FEATURE_PERFMAP
#ifndef DACCESS_COMPILE
-DomainFile::DomainFile(AppDomain *pDomain, PEFile *pFile)
+DomainFile::DomainFile(AppDomain *pDomain, PEAssembly *pPEAssembly)
: m_pDomain(pDomain),
- m_pFile(pFile),
- m_pOriginalFile(NULL),
+ m_pPEAssembly(pPEAssembly),
m_pModule(NULL),
m_level(FILE_LOAD_CREATE),
m_pError(NULL),
@@ -54,7 +53,7 @@ DomainFile::DomainFile(AppDomain *pDomain, PEFile *pFile)
CONTRACTL_END;
m_hExposedModuleObject = NULL;
- pFile->AddRef();
+ pPEAssembly->AddRef();
}
DomainFile::~DomainFile()
@@ -68,9 +67,7 @@ DomainFile::~DomainFile()
}
CONTRACTL_END;
- m_pFile->Release();
- if(m_pOriginalFile)
- m_pOriginalFile->Release();
+ m_pPEAssembly->Release();
if (m_pDynamicMethodTable)
m_pDynamicMethodTable->Destroy();
delete m_pError;
@@ -282,10 +279,10 @@ CHECK DomainFile::CheckLoaded()
// assemblies for bootstrapping purposes. This is because it has no
// dependencies, security checks, and doesn't rely on loader notifications.
- if (GetFile()->IsSystem())
+ if (GetPEAssembly()->IsSystem())
CHECK_OK;
- CHECK_MSG(GetFile()->CheckLoaded(), "PEFile has not been loaded");
+ CHECK_MSG(GetPEAssembly()->IsLoaded(), "PEAssembly has not been loaded");
CHECK_OK;
}
@@ -310,10 +307,10 @@ CHECK DomainFile::CheckActivated()
// assemblies for bootstrapping purposes. This is because it has no
// dependencies, security checks, and doesn't rely on loader notifications.
- if (GetFile()->IsSystem())
+ if (GetPEAssembly()->IsSystem())
CHECK_OK;
- CHECK_MSG(GetFile()->CheckLoaded(), "PEFile has not been loaded");
+ CHECK_MSG(GetPEAssembly()->IsLoaded(), "PEAssembly has not been loaded");
CHECK_MSG(IsLoaded(), "DomainFile has not been fully loaded");
CHECK_MSG(m_bDisableActivationCheck || CheckLoadLevel(FILE_ACTIVE), "File has not had execution verified");
@@ -392,7 +389,7 @@ OBJECTREF DomainFile::GetExposedModuleObject()
GCPROTECT_BEGIN(refClass);
- if (GetFile()->IsDynamic())
+ if (GetPEAssembly()->IsDynamic())
{
refClass = (REFLECTMODULEBASEREF) AllocateObject(CoreLibBinder::GetClass(CLASS__MODULE_BUILDER));
}
@@ -528,7 +525,7 @@ void DomainFile::LoadLibrary()
}
CONTRACTL_END;
- GetFile()->LoadLibrary();
+ GetPEAssembly()->EnsureLoaded();
}
void DomainFile::PostLoadLibrary()
@@ -536,8 +533,8 @@ void DomainFile::PostLoadLibrary()
CONTRACTL
{
INSTANCE_CHECK;
- // Note that GetFile()->LoadLibrary must be called before this OUTSIDE OF THE LOCKS
- PRECONDITION(GetFile()->CheckLoaded());
+ // Note that GetPEAssembly()->EnsureLoaded must be called before this OUTSIDE OF THE LOCKS
+ PRECONDITION(GetPEAssembly()->IsLoaded());
STANDARD_VM_CHECK;
}
CONTRACTL_END;
@@ -597,8 +594,7 @@ void DomainFile::VtableFixups()
{
WRAPPER_NO_CONTRACT;
- if (!GetCurrentModule()->IsResource())
- GetCurrentModule()->FixupVTables();
+ GetCurrentModule()->FixupVTables();
}
void DomainFile::FinishLoad()
@@ -622,7 +618,7 @@ void DomainFile::FinishLoad()
#ifdef FEATURE_PERFMAP
// Notify the perfmap of the IL image load.
- PerfMap::LogImageLoad(m_pFile);
+ PerfMap::LogImageLoad(m_pPEAssembly);
#endif
}
@@ -682,8 +678,8 @@ void DomainFile::Activate()
// DomainAssembly
//--------------------------------------------------------------------------------
-DomainAssembly::DomainAssembly(AppDomain *pDomain, PEFile *pFile, LoaderAllocator *pLoaderAllocator)
- : DomainFile(pDomain, pFile),
+DomainAssembly::DomainAssembly(AppDomain *pDomain, PEAssembly *pPEAssembly, LoaderAllocator *pLoaderAllocator)
+ : DomainFile(pDomain, pPEAssembly),
m_pAssembly(NULL),
m_debuggerFlags(DACF_NONE),
m_fDebuggerUnloadStarted(FALSE),
@@ -700,7 +696,7 @@ DomainAssembly::DomainAssembly(AppDomain *pDomain, PEFile *pFile, LoaderAllocato
}
CONTRACTL_END;
- pFile->ValidateForExecution();
+ pPEAssembly->ValidateForExecution();
// !!! backout
@@ -747,8 +743,9 @@ void DomainAssembly::SetAssembly(Assembly* pAssembly)
{
STANDARD_VM_CONTRACT;
- UpdatePEFile(pAssembly->GetManifestFile());
- _ASSERTE(pAssembly->GetManifestModule()->GetFile()==m_pFile);
+ _ASSERTE(pAssembly->GetManifestModule()->GetPEAssembly()==m_pPEAssembly);
+ _ASSERTE(m_pAssembly == NULL);
+
m_pAssembly = pAssembly;
m_pModule = pAssembly->GetManifestModule();
@@ -793,7 +790,7 @@ OBJECTREF DomainAssembly::GetExposedAssemblyObject()
{
ASSEMBLYREF assemblyObj = NULL;
MethodTable * pMT;
- if (GetFile()->IsDynamic())
+ if (GetPEAssembly()->IsDynamic())
{
// This is unnecessary because the managed InternalAssemblyBuilder object
// should have already been created at the time of DefineDynamicAssembly
@@ -879,18 +876,11 @@ void DomainAssembly::Allocate()
{
//! If you decide to remove "if" do not remove this brace: order is important here - in the case of an exception,
//! the Assembly holder must destruct before the AllocMemTracker declared above.
-
- // We can now rely on the fact that our MDImport will not change so we can stop refcounting it.
- GetFile()->MakeMDImportPersistent();
-
NewHolder assemblyHolder(NULL);
- assemblyHolder = pAssembly = Assembly::Create(m_pDomain, GetFile(), GetDebuggerInfoBits(), this->IsCollectible(), pamTracker, this->IsCollectible() ? this->GetLoaderAllocator() : NULL);
+ assemblyHolder = pAssembly = Assembly::Create(m_pDomain, GetPEAssembly(), GetDebuggerInfoBits(), this->IsCollectible(), pamTracker, this->IsCollectible() ? this->GetLoaderAllocator() : NULL);
assemblyHolder->SetIsTenured();
- //@todo! This is too early to be calling SuppressRelease. The right place to call it is below after
- // the CANNOTTHROWCOMPLUSEXCEPTION. Right now, we have to do this to unblock OOM injection testing quickly
- // as doing the right thing is nontrivial.
pamTracker->SuppressRelease();
assemblyHolder.SuppressRelease();
}
@@ -973,7 +963,7 @@ BOOL DomainAssembly::GetResource(LPCSTR szName, DWORD *cbResource,
}
CONTRACTL_END;
- return GetFile()->GetResource( szName,
+ return GetPEAssembly()->GetResource( szName,
cbResource,
pbInMemoryResource,
pAssemblyRef,
@@ -1048,7 +1038,7 @@ HRESULT DomainAssembly::GetDebuggingCustomAttributes(DWORD *pdwFlags)
ULONG size;
BYTE *blob;
mdModule mdMod;
- ReleaseHolder mdImport(GetFile()->GetMDImportWithRef());
+ IMDInternalImport* mdImport = GetPEAssembly()->GetMDImport();
mdMod = mdImport->GetModuleFromScope();
mdAssembly asTK = TokenFromRid(mdtAssembly, 1);
@@ -1202,9 +1192,9 @@ DomainFile::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
// so we don't need to duplicate effort; thus we do noting with m_pModule.
// For MiniDumpNormal, we only want the file name.
- if (m_pFile.IsValid())
+ if (m_pPEAssembly.IsValid())
{
- m_pFile->EnumMemoryRegions(flags);
+ m_pPEAssembly->EnumMemoryRegions(flags);
}
if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE
diff --git a/src/coreclr/vm/domainfile.h b/src/coreclr/vm/domainfile.h
index 4396ad6c8d990..49a8344b21e84 100644
--- a/src/coreclr/vm/domainfile.h
+++ b/src/coreclr/vm/domainfile.h
@@ -87,23 +87,16 @@ class DomainFile
return m_pDomain;
}
- PEFile *GetFile()
+ PEAssembly *GetPEAssembly()
{
LIMITED_METHOD_DAC_CONTRACT;
- return m_pFile;
+ return PTR_PEAssembly(m_pPEAssembly);
}
- PEFile *GetOriginalFile()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return m_pOriginalFile!= NULL ? m_pOriginalFile : m_pFile;
- }
-
-
IMDInternalImport *GetMDImport()
{
WRAPPER_NO_CONTRACT;
- return m_pFile->GetPersistentMDImport();
+ return m_pPEAssembly->GetMDImport();
}
OBJECTREF GetExposedModuleObjectIfExists()
@@ -120,20 +113,20 @@ class DomainFile
BOOL IsSystem()
{
WRAPPER_NO_CONTRACT;
- return GetFile()->IsSystem();
+ return GetPEAssembly()->IsSystem();
}
LPCUTF8 GetSimpleName()
{
WRAPPER_NO_CONTRACT;
- return GetFile()->GetSimpleName();
+ return GetPEAssembly()->GetSimpleName();
}
#ifdef LOGGING
LPCWSTR GetDebugName()
{
WRAPPER_NO_CONTRACT;
- return GetFile()->GetDebugName();
+ return GetPEAssembly()->GetDebugName();
}
#endif
@@ -252,8 +245,8 @@ class DomainFile
// ------------------------------------------------------------
#ifndef DACCESS_COMPILE
- BOOL Equals(DomainFile *pFile) { WRAPPER_NO_CONTRACT; return GetFile()->Equals(pFile->GetFile()); }
- BOOL Equals(PEFile *pFile) { WRAPPER_NO_CONTRACT; return GetFile()->Equals(pFile); }
+ BOOL Equals(DomainFile *pFile) { WRAPPER_NO_CONTRACT; return GetPEAssembly()->Equals(pFile->GetPEAssembly()); }
+ BOOL Equals(PEAssembly *pPEAssembly) { WRAPPER_NO_CONTRACT; return GetPEAssembly()->Equals(pPEAssembly); }
#endif // DACCESS_COMPILE
Module* GetCurrentModule();
@@ -279,7 +272,7 @@ class DomainFile
friend class Module;
friend class FileLoadLock;
- DomainFile(AppDomain *pDomain, PEFile *pFile);
+ DomainFile(AppDomain *pDomain, PEAssembly *pPEAssembly);
BOOL DoIncrementalLoad(FileLoadLevel targetLevel);
void ClearLoading() { LIMITED_METHOD_CONTRACT; m_loading = FALSE; }
@@ -306,17 +299,13 @@ class DomainFile
void SetProfilerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|= PROFILER_NOTIFIED; }
void SetDebuggerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NOTIFIED; }
void SetShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NEEDNOTIFICATION; }
-#ifndef DACCESS_COMPILE
- void UpdatePEFileWorker(PTR_PEFile pFile);
-#endif
// ------------------------------------------------------------
// Instance data
// ------------------------------------------------------------
PTR_AppDomain m_pDomain;
- PTR_PEFile m_pFile;
- PTR_PEFile m_pOriginalFile; // keep file alive just in case someone is sitill using it. If this is not NULL then m_pFile contains reused file from the shared assembly
+ PTR_PEAssembly m_pPEAssembly;
PTR_Module m_pModule;
FileLoadLevel m_level;
LOADERHANDLE m_hExposedModuleObject;
@@ -425,12 +414,6 @@ class DomainAssembly : public DomainFile
// Public API
// ------------------------------------------------------------
- PEAssembly *GetFile()
- {
- LIMITED_METHOD_CONTRACT;
- return PTR_PEAssembly(m_pFile);
- }
-
LoaderAllocator *GetLoaderAllocator()
{
LIMITED_METHOD_CONTRACT;
@@ -592,7 +575,7 @@ class DomainAssembly : public DomainFile
public:
~DomainAssembly();
private:
- DomainAssembly(AppDomain *pDomain, PEFile *pFile, LoaderAllocator *pLoaderAllocator);
+ DomainAssembly(AppDomain *pDomain, PEAssembly *pPEAssembly, LoaderAllocator *pLoaderAllocator);
#endif
// ------------------------------------------------------------
@@ -606,10 +589,6 @@ class DomainAssembly : public DomainFile
void DeliverAsyncEvents();
#endif
- void UpdatePEFile(PTR_PEFile pFile);
-
- BOOL IsInstrumented();
-
public:
ULONG HashIdentity();
diff --git a/src/coreclr/vm/domainfile.inl b/src/coreclr/vm/domainfile.inl
index 91ed0ae4a1ff3..a87d9aaef1309 100644
--- a/src/coreclr/vm/domainfile.inl
+++ b/src/coreclr/vm/domainfile.inl
@@ -58,39 +58,10 @@ inline Assembly* DomainAssembly::GetAssembly()
return m_pAssembly;
}
-#ifndef DACCESS_COMPILE
-inline void DomainFile::UpdatePEFileWorker(PTR_PEFile pFile)
-{
- LIMITED_METHOD_CONTRACT;
- CONSISTENCY_CHECK(CheckPointer(pFile));
- if (pFile==m_pFile)
- return;
- _ASSERTE(m_pOriginalFile==NULL);
- m_pOriginalFile=m_pFile;
- pFile->AddRef();
- m_pFile=pFile;
-}
-
-inline void DomainAssembly::UpdatePEFile(PTR_PEFile pFile)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- GetAppDomain()->UpdatePublishHostedAssembly(this, pFile);
-}
-
-#endif // DACCESS_COMPILE
-
inline ULONG DomainAssembly::HashIdentity()
{
WRAPPER_NO_CONTRACT;
- return GetFile()->HashIdentity();
+ return GetPEAssembly()->HashIdentity();
}
inline BOOL DomainAssembly::IsCollectible()
diff --git a/src/coreclr/vm/dwbucketmanager.hpp b/src/coreclr/vm/dwbucketmanager.hpp
index cf360ac7322a5..21267b8f36070 100644
--- a/src/coreclr/vm/dwbucketmanager.hpp
+++ b/src/coreclr/vm/dwbucketmanager.hpp
@@ -701,14 +701,14 @@ void BaseBucketParamsManager::GetModuleTimeStamp(__out_ecount(maxLength) WCHAR*
{
// We only store the IL timestamp in the native image for the
// manifest module. We should consider fixing this for Orcas.
- PTR_PEFile pFile = pModule->GetAssembly()->GetManifestModule()->GetFile();
+ PTR_PEAssembly pFile = pModule->GetAssembly()->GetManifestModule()->GetPEAssembly();
// for dynamic modules use 0 as the time stamp
ULONG ulTimeStamp = 0;
if (!pFile->IsDynamic())
{
- ulTimeStamp = pFile->GetILImageTimeDateStamp();
+ ulTimeStamp = pFile->GetPEImageTimeDateStamp();
_ASSERTE(ulTimeStamp != 0);
}
@@ -957,13 +957,13 @@ bool BaseBucketParamsManager::GetFileVersionInfoForModule(Module* pModule, USHOR
bool succeeded = false;
- PEFile* pFile = pModule->GetFile();
- if (pFile)
+ PEAssembly* pPEAssembly = pModule->GetPEAssembly();
+ if (pPEAssembly)
{
// if we failed to get the version info from the native image then fall back to the IL image.
if (!succeeded)
{
- LPCWSTR modulePath = pFile->GetPath().GetUnicode();
+ LPCWSTR modulePath = pPEAssembly->GetPath().GetUnicode();
if (modulePath != NULL && modulePath != SString::Empty() && SUCCEEDED(DwGetFileVersionInfo(modulePath, major, minor, build, revision)))
{
succeeded = true;
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index a93343b112a41..5abf6c7d87c9a 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -314,7 +314,6 @@ FCFuncStart(gCOMModuleFuncs)
QCFuncElement("GetScopeName", COMModule::GetScopeName)
FCFuncElement("GetTypes", COMModule::GetTypes)
QCFuncElement("GetFullyQualifiedName", COMModule::GetFullyQualifiedName)
- FCFuncElement("IsResource", COMModule::IsResource)
FCFuncEnd()
FCFuncStart(gCOMModuleBuilderFuncs)
diff --git a/src/coreclr/vm/eedbginterfaceimpl.h b/src/coreclr/vm/eedbginterfaceimpl.h
index d4d790c9e886f..72594c336794c 100644
--- a/src/coreclr/vm/eedbginterfaceimpl.h
+++ b/src/coreclr/vm/eedbginterfaceimpl.h
@@ -26,7 +26,7 @@
#include "debugdebugger.h"
#include "eeconfig.h"
-#include "pefile.h"
+#include "peassembly.h"
class EEDbgInterfaceImpl : public EEDebugInterface
{
diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp
index b11e2d8437068..3f745d299427c 100644
--- a/src/coreclr/vm/encee.cpp
+++ b/src/coreclr/vm/encee.cpp
@@ -35,8 +35,8 @@ static int g_BreakOnEnCResolveField = -1;
// The constructor phase initializes just enough so that Destruct() can be safely called.
// It cannot throw or fail.
//
-EditAndContinueModule::EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEFile *file)
- : Module(pAssembly, moduleRef, file)
+EditAndContinueModule::EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEAssembly *pPEAssembly)
+ : Module(pAssembly, moduleRef, pPEAssembly)
{
CONTRACTL
{
@@ -175,7 +175,7 @@ HRESULT EditAndContinueModule::ApplyEditAndContinue(
{
// ConvertMDInternalToReadWrite should only ever be called on EnC capable files.
_ASSERTE(IsEditAndContinueCapable()); // this also checks that the file is EnC capable
- GetFile()->ConvertMDInternalToReadWrite();
+ GetPEAssembly()->ConvertMDInternalToReadWrite();
}
EX_CATCH_HRESULT(hr);
diff --git a/src/coreclr/vm/encee.h b/src/coreclr/vm/encee.h
index 2c7a834f32803..bd20a4057651a 100644
--- a/src/coreclr/vm/encee.h
+++ b/src/coreclr/vm/encee.h
@@ -202,13 +202,13 @@ class EditAndContinueModule : public Module
// Return the minimum permissable address for new IL to be stored at
// This can't be less than the current load address because then we'd
// have negative RVAs.
- BYTE *GetEnCBase() { return (BYTE *) GetFile()->GetManagedFileContents(); }
+ BYTE *GetEnCBase() { return (BYTE *) GetPEAssembly()->GetManagedFileContents(); }
#endif // DACCESS_COMPILE
private:
// Constructor is invoked only by Module::Create
- friend Module *Module::Create(Assembly *pAssembly, mdToken moduleRef, PEFile *file, AllocMemTracker *pamTracker);
- EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEFile *file);
+ friend Module *Module::Create(Assembly *pAssembly, mdToken moduleRef, PEAssembly *pPEAssembly, AllocMemTracker *pamTracker);
+ EditAndContinueModule(Assembly *pAssembly, mdToken moduleRef, PEAssembly *pPEAssembly);
protected:
#ifndef DACCESS_COMPILE
diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp
index dd36960e257e5..c549018584d70 100644
--- a/src/coreclr/vm/eventtrace.cpp
+++ b/src/coreclr/vm/eventtrace.cpp
@@ -6135,13 +6135,13 @@ static void GetCodeViewInfo(Module * pModule, CV_INFO_PDB70 * pCvInfoIL, CV_INFO
ZeroMemory(pCvInfoIL, sizeof(*pCvInfoIL));
ZeroMemory(pCvInfoNative, sizeof(*pCvInfoNative));
- PTR_PEFile pPEFile = pModule->GetFile();
- _ASSERTE(pPEFile != NULL);
+ PTR_PEAssembly pPEAssembly = pModule->GetPEAssembly();
+ _ASSERTE(pPEAssembly != NULL);
PTR_PEImageLayout pLayout = NULL;
- if (pPEFile->HasOpenedILimage())
+ if (pPEAssembly->HasPEImage())
{
- pLayout = pPEFile->GetLoadedIL();
+ pLayout = pPEAssembly->GetLoadedLayout();
}
if (pLayout == NULL)
@@ -6338,7 +6338,7 @@ VOID ETW::LoaderLog::SendModuleEvent(Module *pModule, DWORD dwEventOptions, BOOL
if(!bIsDynamicAssembly)
{
- ModuleILPath = (PWCHAR)pModule->GetAssembly()->GetManifestFile()->GetILimage()->GetPath().GetUnicode();
+ ModuleILPath = (PWCHAR)pModule->GetAssembly()->GetManifestFile()->GetPEImage()->GetPath().GetUnicode();
ModuleNativePath = (PWCHAR)pEmptyString;
}
diff --git a/src/coreclr/vm/exceptmacros.h b/src/coreclr/vm/exceptmacros.h
index 1eba8ca9c47fc..70e1fe0871e0d 100644
--- a/src/coreclr/vm/exceptmacros.h
+++ b/src/coreclr/vm/exceptmacros.h
@@ -520,7 +520,7 @@ VOID ThrowBadFormatWorkerT(UINT resID, T * pImgObj DEBUGARG(__in_z const char *c
// Worker macro for throwing BadImageFormat exceptions.
//
// resID: resource ID in mscorrc.rc. Message may not have substitutions. resID is permitted (but not encouraged) to be 0.
-// imgObj: one of Module* or PEFile* or PEImage* (must support GetPathForErrorMessages method.)
+// imgObj: one of Module* or PEAssembly* or PEImage* (must support GetPathForErrorMessages method.)
//
#define IfFailThrowBF(hresult, resID, imgObj) \
do \
diff --git a/src/coreclr/vm/inlinetracking.cpp b/src/coreclr/vm/inlinetracking.cpp
index bfd420850c1bd..86d73ea0a7657 100644
--- a/src/coreclr/vm/inlinetracking.cpp
+++ b/src/coreclr/vm/inlinetracking.cpp
@@ -45,7 +45,7 @@ bool MethodInModule::operator <(const MethodInModule& other) const
}
else
{
- m_module->GetFile()->GetMVID(&thisGuid);
+ m_module->GetPEAssembly()->GetMVID(&thisGuid);
}
if (other.m_module == NULL)
@@ -54,7 +54,7 @@ bool MethodInModule::operator <(const MethodInModule& other) const
}
else
{
- other.m_module->GetFile()->GetMVID(&otherGuid);
+ other.m_module->GetPEAssembly()->GetMVID(&otherGuid);
}
return memcmp(&thisGuid, &otherGuid, sizeof(GUID)) < 0;
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 9b6023b4d98d0..3ffb87896fa96 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -984,7 +984,7 @@ void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken
ThrowBadTokenException(pResolvedToken);
{
- DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
+ DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK);
if (pTargetModule == NULL)
COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
@@ -7798,14 +7798,14 @@ void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
if (LoggingOn(LF_JIT, LL_INFO100000))
{
SString currentMethodName;
- currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
+ currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetPEAssembly()->GetSimpleName());
currentMethodName.Append(L'/');
TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
SString inlineeMethodName;
if (GetMethod(inlineeHnd))
{
- inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
+ inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetPEAssembly()->GetSimpleName());
inlineeMethodName.Append(L'/');
TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
}
@@ -7817,7 +7817,7 @@ void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
SString inlinerMethodName;
if (GetMethod(inlinerHnd))
{
- inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
+ inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetPEAssembly()->GetSimpleName());
inlinerMethodName.Append(L'/');
TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
}
@@ -12815,7 +12815,7 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
LARGE_INTEGER methodJitTimeStop;
QueryPerformanceCounter(&methodJitTimeStop);
SString codeBase;
- ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
+ ftn->GetModule()->GetDomainFile()->GetPEAssembly()->GetPathOrCodeBase(codeBase);
codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
//(const WCHAR *)codeBase, //module name
ftn->GetMemberDef(), //method token
diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp
index f30f3f83daecd..d92fba38536e5 100644
--- a/src/coreclr/vm/loaderallocator.cpp
+++ b/src/coreclr/vm/loaderallocator.cpp
@@ -481,9 +481,9 @@ LoaderAllocator * LoaderAllocator::GCLoaderAllocators_RemoveAssemblies(AppDomain
if (!domainAssemblyToRemove->GetAssembly()->IsDynamic())
{
- pAppDomain->RemoveFileFromCache(domainAssemblyToRemove->GetFile());
+ pAppDomain->RemoveFileFromCache(domainAssemblyToRemove->GetPEAssembly());
AssemblySpec spec;
- spec.InitializeSpec(domainAssemblyToRemove->GetFile());
+ spec.InitializeSpec(domainAssemblyToRemove->GetPEAssembly());
VERIFY(pAppDomain->RemoveAssemblyFromCache(domainAssemblyToRemove));
}
diff --git a/src/coreclr/vm/memberload.cpp b/src/coreclr/vm/memberload.cpp
index ce53bf22589f8..78fdb518a1618 100644
--- a/src/coreclr/vm/memberload.cpp
+++ b/src/coreclr/vm/memberload.cpp
@@ -277,7 +277,7 @@ void MemberLoader::GetDescFromMemberRef(Module * pModule,
{
case mdtModuleRef:
{
- DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), parent, FALSE /* loadResources */);
+ DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), parent);
if (pTargetModule == NULL)
COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
typeHnd = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
diff --git a/src/coreclr/vm/methoditer.cpp b/src/coreclr/vm/methoditer.cpp
index 5bd7e81f5de2d..841b3214d2e2d 100644
--- a/src/coreclr/vm/methoditer.cpp
+++ b/src/coreclr/vm/methoditer.cpp
@@ -83,9 +83,6 @@ BOOL LoadedMethodDescIterator::Next(
if (!m_moduleIterator.Next())
goto ADVANCE_ASSEMBLY;
- if (GetCurrentModule()->IsResource())
- goto ADVANCE_MODULE;
-
if (m_mainMD->HasClassInstantiation())
{
m_typeIterator.Reset();
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 8751224545933..90f451a1dfde1 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -4337,9 +4337,8 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
DWORD rva;
IfFailThrow(pInternalImport->GetFieldRVA(pFD->GetMemberDef(), &rva));
- // Ensure that the IL image is loaded. Note that this assembly may
- // have an ngen image, but this type may have failed to load during ngen.
- GetModule()->GetFile()->LoadLibrary(FALSE);
+ // Ensure that the IL image is loaded.
+ GetModule()->GetPEAssembly()->EnsureLoaded();
DWORD fldSize;
if (FieldDescElementType == ELEMENT_TYPE_VALUETYPE)
@@ -11216,7 +11215,7 @@ BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
// Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
// whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
// ReadyToRun images with and without input bubble enabled.
- if (!GetModule()->GetFile()->IsReadyToRun())
+ if (!GetModule()->GetPEAssembly()->IsReadyToRun())
{
// Always use ReadyToRun field layout algorithm to produce ReadyToRun images
return FALSE;
diff --git a/src/coreclr/vm/multicorejit.cpp b/src/coreclr/vm/multicorejit.cpp
index b94be184959d7..e66e6e39d8f49 100644
--- a/src/coreclr/vm/multicorejit.cpp
+++ b/src/coreclr/vm/multicorejit.cpp
@@ -255,25 +255,20 @@ bool ModuleVersion::GetModuleVersion(Module * pModule)
// GetMVID can throw exception
EX_TRY
{
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pAsm = pModule->GetPEAssembly();
- if (pFile != NULL)
+ if (pAsm != NULL)
{
- PEAssembly * pAsm = pFile->GetAssembly();
+ // CorAssemblyFlags, only 16-bit used
+ versionFlags = pAsm->GetFlags();
- if (pAsm != NULL)
- {
- // CorAssemblyFlags, only 16-bit used
- versionFlags = pAsm->GetFlags();
-
- _ASSERTE((versionFlags & 0x80000000) == 0);
+ _ASSERTE((versionFlags & 0x80000000) == 0);
- pAsm->GetVersion(& major, & minor, & build, & revision);
+ pAsm->GetVersion(&major, &minor, &build, &revision);
- pAsm->GetMVID(& mvid);
+ pAsm->GetMVID(&mvid);
- hr = S_OK;
- }
+ hr = S_OK;
}
// If the load context is LOADFROM, store it in the flags.
diff --git a/src/coreclr/vm/multicorejitplayer.cpp b/src/coreclr/vm/multicorejitplayer.cpp
index d84ed388c9c44..7aae1dadaf873 100644
--- a/src/coreclr/vm/multicorejitplayer.cpp
+++ b/src/coreclr/vm/multicorejitplayer.cpp
@@ -396,11 +396,6 @@ bool MulticoreJitManager::ModuleHasNoCode(Module * pModule)
{
LIMITED_METHOD_CONTRACT;
- if (pModule->IsResource())
- {
- return true;
- }
-
IMDInternalImport * pImport = pModule->GetMDImport();
if (pImport != NULL)
@@ -434,15 +429,15 @@ bool MulticoreJitManager::IsSupportedModule(Module * pModule, bool fMethodJit)
return false;
}
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pPEAssembly = pModule->GetPEAssembly();
// dynamic module.
- if (pFile->IsDynamic()) // Ignore dynamic modules
+ if (pPEAssembly->IsDynamic()) // Ignore dynamic modules
{
return false;
}
- if (pFile->GetPath().IsEmpty()) // Ignore in-memory modules
+ if (pPEAssembly->GetPath().IsEmpty()) // Ignore in-memory modules
{
return false;
}
diff --git a/src/coreclr/vm/nativeimage.cpp b/src/coreclr/vm/nativeimage.cpp
index 13a39a2d4666e..b081091f1b94e 100644
--- a/src/coreclr/vm/nativeimage.cpp
+++ b/src/coreclr/vm/nativeimage.cpp
@@ -146,8 +146,9 @@ NativeImage *NativeImage::Open(
BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(fullPath, /*pathIsBundleRelative */ true);
if (bundleFileLocation.IsValid())
{
- PEImageHolder pImage = PEImage::OpenImage(fullPath, MDInternalImport_NoCache, bundleFileLocation);
- peLoadedImage = pImage->GetLayout(PEImageLayout::LAYOUT_MAPPED, PEImage::LAYOUT_CREATEIFNEEDED);
+ PEImageHolder pImage = PEImage::OpenImage(fullPath, MDInternalImport_Default, bundleFileLocation);
+ peLoadedImage = pImage->GetOrCreateLayout(PEImageLayout::LAYOUT_MAPPED);
+ peLoadedImage.SuppressRelease();
}
if (peLoadedImage.IsNull())
diff --git a/src/coreclr/vm/nativeimage.h b/src/coreclr/vm/nativeimage.h
index bf3f7b6272edf..4774365197f2b 100644
--- a/src/coreclr/vm/nativeimage.h
+++ b/src/coreclr/vm/nativeimage.h
@@ -57,7 +57,7 @@ class NativeImageIndexTraits : public NoRemoveSHashTraitsGetManifestFile();
+ PEAssembly *pManifestFile = pAssembly->GetManifestFile();
PTR_AssemblyBinder pBinder = pManifestFile->GetAssemblyBinder();
//Step 0: Check if the assembly was bound using TPA.
diff --git a/src/coreclr/vm/pefile.cpp b/src/coreclr/vm/peassembly.cpp
similarity index 67%
rename from src/coreclr/vm/pefile.cpp
rename to src/coreclr/vm/peassembly.cpp
index 8e7d70732a27f..956512a3dbe06 100644
--- a/src/coreclr/vm/pefile.cpp
+++ b/src/coreclr/vm/peassembly.cpp
@@ -1,14 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// --------------------------------------------------------------------------------
-// PEFile.cpp
+// PEAssembly.cpp
//
// --------------------------------------------------------------------------------
#include "common.h"
-#include "pefile.h"
+#include "peassembly.h"
#include "eecontract.h"
#include "eeconfig.h"
#include "eventtrace.h"
@@ -28,127 +28,19 @@
#ifndef DACCESS_COMPILE
-// ================================================================================
-// PEFile class - this is an abstract base class for PEAssembly
-// ================================================================================
-
-PEFile::PEFile(PEImage *identity) :
-#if _DEBUG
- m_pDebugName(NULL),
-#endif
- m_identity(NULL),
- m_openedILimage(NULL),
- m_MDImportIsRW_Debugger_Use_Only(FALSE),
- m_bHasPersistentMDImport(FALSE),
- m_pMDImport(NULL),
- m_pImporter(NULL),
- m_pEmitter(NULL),
- m_pMetadataLock(::new SimpleRWLock(PREEMPTIVE, LOCK_TYPE_DEFAULT)),
- m_refCount(1),
- m_flags(0),
- m_pHostAssembly(nullptr),
- m_pFallbackBinder(nullptr)
-{
- CONTRACTL
- {
- CONSTRUCTOR_CHECK;
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (identity)
- {
- identity->AddRef();
- m_identity = identity;
-
- if(identity->IsOpened())
- {
- //already opened, prepopulate
- identity->AddRef();
- m_openedILimage = identity;
- }
- }
-
-
-}
-
-
-
-PEFile::~PEFile()
-{
- CONTRACTL
- {
- DESTRUCTOR_CHECK;
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ReleaseMetadataInterfaces(TRUE);
-
-
- if (m_openedILimage != NULL)
- m_openedILimage->Release();
- if (m_identity != NULL)
- m_identity->Release();
- if (m_pMetadataLock)
- delete m_pMetadataLock;
-
- if (m_pHostAssembly != NULL)
- {
- m_pHostAssembly->Release();
- }
-}
-
-/* static */
-PEFile *PEFile::Open(PEImage *image)
-{
- CONTRACT(PEFile *)
- {
- PRECONDITION(image != NULL);
- PRECONDITION(image->CheckFormat());
- POSTCONDITION(RETVAL != NULL);
- POSTCONDITION(!RETVAL->IsAssembly());
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACT_END;
-
- PEFile *pFile = new PEFile(image);
-
- if (image->HasNTHeaders() && image->HasCorHeader())
- pFile->OpenMDImport_Unsafe(); //no one else can see the object yet
-
-#if _DEBUG
- pFile->m_debugName = image->GetPath();
- pFile->m_debugName.Normalize();
- pFile->m_pDebugName = pFile->m_debugName;
-#endif
-
- RETURN pFile;
-}
-
//-----------------------------------------------------------------------------------------------------
// Catch attempts to load x64 assemblies on x86, etc.
//-----------------------------------------------------------------------------------------------------
-static void ValidatePEFileMachineType(PEFile *peFile)
+static void ValidatePEFileMachineType(PEAssembly *pPEAssembly)
{
STANDARD_VM_CONTRACT;
- if (peFile->IsDynamic())
+ if (pPEAssembly->IsDynamic())
return; // PEFiles for ReflectionEmit assemblies don't cache the machine type.
- if (peFile->IsResource())
- return; // PEFiles for resource assemblies don't cache the machine type.
-
DWORD peKind;
DWORD actualMachineType;
- peFile->GetPEKindAndMachine(&peKind, &actualMachineType);
+ pPEAssembly->GetPEKindAndMachine(&peKind, &actualMachineType);
if (actualMachineType == IMAGE_FILE_MACHINE_I386 && ((peKind & (peILonly | pe32BitRequired)) == peILonly))
return; // Image is marked CPU-agnostic.
@@ -167,10 +59,7 @@ static void ValidatePEFileMachineType(PEFile *peFile)
// Image has required machine that doesn't match the CLR.
StackSString name;
- if (peFile->IsAssembly())
- ((PEAssembly*)peFile)->GetDisplayName(name);
- else
- name = StackSString(SString::Utf8, peFile->GetSimpleName());
+ pPEAssembly->GetDisplayName(name);
COMPlusThrow(kBadImageFormatException, IDS_CLASSLOAD_WRONGCPU, name.GetUnicode());
}
@@ -178,12 +67,12 @@ static void ValidatePEFileMachineType(PEFile *peFile)
return; // If we got here, all is good.
}
-void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==FALSE force IL image load
+void PEAssembly::EnsureLoaded()
{
CONTRACT_VOID
{
INSTANCE_CHECK;
- POSTCONDITION(CheckLoaded());
+ POSTCONDITION(IsLoaded());
STANDARD_VM_CHECK;
}
CONTRACT_END;
@@ -191,142 +80,64 @@ void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==F
// Catch attempts to load x64 assemblies on x86, etc.
ValidatePEFileMachineType(this);
- // See if we've already loaded it.
- if (CheckLoaded(allowNativeSkip))
+ // See if we do not have anything to load or have already loaded it.
+ if (IsLoaded())
{
RETURN;
}
// Note that we may be racing other threads here, in the case of domain neutral files
- // Resource images are always flat.
- if (IsResource())
- {
- GetILimage()->LoadNoMetaData();
- RETURN;
- }
-
#if !defined(TARGET_64BIT)
- if (!GetILimage()->Has32BitNTHeaders())
+ if (!GetPEImage()->Has32BitNTHeaders())
{
// Tried to load 64-bit assembly on 32-bit platform.
EEFileLoadException::Throw(this, COR_E_BADIMAGEFORMAT, NULL);
}
#endif
- // We need contents now
- EnsureImageOpened();
-
// Since we couldn't call LoadLibrary, we must be an IL only image
// or the image may still contain unfixed up stuff
- if (!GetILimage()->IsILOnly())
+ if (!GetPEImage()->IsILOnly())
{
- if (!GetILimage()->HasV1Metadata())
+ if (!GetPEImage()->HasV1Metadata())
ThrowHR(COR_E_FIXUPSINEXE); // @todo: better error
}
- if (GetILimage()->IsFile())
+ if (GetPEImage()->IsFile())
{
#ifdef TARGET_UNIX
- bool loadILImage = GetILimage()->IsILOnly();
+ bool loadILImage = GetPEImage()->IsILOnly();
#else // TARGET_UNIX
- bool loadILImage = GetILimage()->IsILOnly() && GetILimage()->IsInBundle();
+ bool loadILImage = GetPEImage()->IsILOnly() && GetPEImage()->IsInBundle();
#endif // TARGET_UNIX
if (loadILImage)
{
- GetILimage()->Load();
+ GetPEImage()->Load();
}
else
{
- GetILimage()->LoadFromMapped();
+ GetPEImage()->LoadFromMapped();
}
}
else
{
- GetILimage()->LoadNoFile();
- }
-
- RETURN;
-}
-
-void PEFile::SetLoadedHMODULE(HMODULE hMod)
-{
- CONTRACT_VOID
- {
- INSTANCE_CHECK;
- PRECONDITION(CheckPointer(hMod));
- POSTCONDITION(CheckLoaded());
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
+ GetPEImage()->LoadNoFile();
}
- CONTRACT_END;
-
- // See if the image is an internal PEImage.
- GetILimage()->SetLoadedHMODULE(hMod);
RETURN;
}
-/* static */
-void PEFile::DefineEmitScope(
- GUID iid,
- void **ppEmit)
-{
- CONTRACT_VOID
- {
- PRECONDITION(CheckPointer(ppEmit));
- POSTCONDITION(CheckPointer(*ppEmit));
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACT_END;
-
- SafeComHolder pDispenser;
-
- // Get the Dispenser interface.
- MetaDataGetDispenser(
- CLSID_CorMetaDataDispenser,
- IID_IMetaDataDispenserEx,
- (void **)&pDispenser);
- if (pDispenser == NULL)
- {
- ThrowOutOfMemory();
- }
-
- // Set the option on the dispenser turn on duplicate check for TypeDef and moduleRef
- VARIANT varOption;
- V_VT(&varOption) = VT_UI4;
- V_I4(&varOption) = MDDupDefault | MDDupTypeDef | MDDupModuleRef | MDDupExportedType | MDDupAssemblyRef | MDDupPermission | MDDupFile;
- IfFailThrow(pDispenser->SetOption(MetaDataCheckDuplicatesFor, &varOption));
-
- // Set minimal MetaData size
- V_VT(&varOption) = VT_UI4;
- V_I4(&varOption) = MDInitialSizeMinimal;
- IfFailThrow(pDispenser->SetOption(MetaDataInitialSize, &varOption));
-
- // turn on the thread safety!
- V_I4(&varOption) = MDThreadSafetyOn;
- IfFailThrow(pDispenser->SetOption(MetaDataThreadSafetyOptions, &varOption));
-
- IfFailThrow(pDispenser->DefineScope(CLSID_CorMetaDataRuntime, 0, iid, (IUnknown **)ppEmit));
-
- RETURN;
-} // PEFile::DefineEmitScope
-
// ------------------------------------------------------------
// Identity
// ------------------------------------------------------------
-BOOL PEFile::Equals(PEFile *pFile)
+BOOL PEAssembly::Equals(PEAssembly *pPEAssembly)
{
CONTRACTL
{
INSTANCE_CHECK;
- PRECONDITION(CheckPointer(pFile));
+ PRECONDITION(CheckPointer(pPEAssembly));
GC_NOTRIGGER;
NOTHROW;
CANNOT_TAKE_LOCK;
@@ -335,36 +146,31 @@ BOOL PEFile::Equals(PEFile *pFile)
CONTRACTL_END;
// Same object is equal
- if (pFile == this)
+ if (pPEAssembly == this)
return TRUE;
// Different host assemblies cannot be equal unless they are associated with the same host binder
// It's ok if only one has a host binder because multiple threads can race to load the same assembly
// and that may cause temporary candidate PEAssembly objects that never get bound to a host assembly
// because another thread beats it; the losing thread will pick up the PEAssembly in the cache.
- if (pFile->HasHostAssembly() && this->HasHostAssembly())
+ if (pPEAssembly->HasHostAssembly() && this->HasHostAssembly())
{
- AssemblyBinder* fileBinder = pFile->GetHostAssembly()->GetBinder();
+ AssemblyBinder* otherBinder = pPEAssembly->GetHostAssembly()->GetBinder();
AssemblyBinder* thisBinder = this->GetHostAssembly()->GetBinder();
- if (fileBinder != thisBinder || fileBinder == NULL)
+ if (otherBinder != thisBinder || otherBinder == NULL)
return FALSE;
}
- // Same identity is equal
- if (m_identity != NULL && pFile->m_identity != NULL
- && m_identity->Equals(pFile->m_identity))
- return TRUE;
-
// Same image is equal
- if (m_openedILimage != NULL && pFile->m_openedILimage != NULL
- && m_openedILimage->Equals(pFile->m_openedILimage))
+ if (m_PEImage != NULL && pPEAssembly->m_PEImage != NULL
+ && m_PEImage->Equals(pPEAssembly->m_PEImage))
return TRUE;
return FALSE;
}
-BOOL PEFile::Equals(PEImage *pImage)
+BOOL PEAssembly::Equals(PEImage *pImage)
{
CONTRACTL
{
@@ -376,21 +182,15 @@ BOOL PEFile::Equals(PEImage *pImage)
}
CONTRACTL_END;
- // Same object is equal
- if (pImage == m_identity || pImage == m_openedILimage)
+ // Same image ==> equal
+ if (pImage == m_PEImage)
return TRUE;
- // Same identity is equal
- if (m_identity != NULL
- && m_identity->Equals(pImage))
+ // Equal image ==> equal
+ if (m_PEImage != NULL
+ && m_PEImage->Equals(pImage))
return TRUE;
- // Same image is equal
- if (m_openedILimage != NULL
- && m_openedILimage->Equals(pImage))
- return TRUE;
-
-
return FALSE;
}
@@ -398,7 +198,7 @@ BOOL PEFile::Equals(PEImage *pImage)
// Descriptive strings
// ------------------------------------------------------------
-void PEFile::GetCodeBaseOrName(SString &result)
+void PEAssembly::GetPathOrCodeBase(SString &result)
{
CONTRACTL
{
@@ -410,47 +210,21 @@ void PEFile::GetCodeBaseOrName(SString &result)
}
CONTRACTL_END;
- if (m_identity != NULL && !m_identity->GetPath().IsEmpty())
- {
- result.Set(m_identity->GetPath());
- }
- else if (IsAssembly())
+ if (m_PEImage != NULL && !m_PEImage->GetPath().IsEmpty())
{
- ((PEAssembly*)this)->GetCodeBase(result);
+ result.Set(m_PEImage->GetPath());
}
else
- result.SetUTF8(GetSimpleName());
-}
-
-
-// ------------------------------------------------------------
-// Checks
-// ------------------------------------------------------------
-
-
-
-CHECK PEFile::CheckLoaded(BOOL bAllowNativeSkip/*=TRUE*/)
-{
- CONTRACT_CHECK
{
- INSTANCE_CHECK;
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
+ GetCodeBase(result);
}
- CONTRACT_CHECK_END;
-
- CHECK(IsLoaded(bAllowNativeSkip));
-
- CHECK_OK;
}
-
// ------------------------------------------------------------
// Metadata access
// ------------------------------------------------------------
-PTR_CVOID PEFile::GetMetadata(COUNT_T *pSize)
+PTR_CVOID PEAssembly::GetMetadata(COUNT_T *pSize)
{
CONTRACT(PTR_CVOID)
{
@@ -465,8 +239,8 @@ PTR_CVOID PEFile::GetMetadata(COUNT_T *pSize)
CONTRACT_END;
if (IsDynamic()
- || !GetILimage()->HasNTHeaders()
- || !GetILimage()->HasCorHeader())
+ || !GetPEImage()->HasNTHeaders()
+ || !GetPEImage()->HasCorHeader())
{
if (pSize != NULL)
*pSize = 0;
@@ -474,12 +248,12 @@ PTR_CVOID PEFile::GetMetadata(COUNT_T *pSize)
}
else
{
- RETURN GetILimage()->GetMetadata(pSize);
+ RETURN GetPEImage()->GetMetadata(pSize);
}
}
#endif // #ifndef DACCESS_COMPILE
-PTR_CVOID PEFile::GetLoadedMetadata(COUNT_T *pSize)
+PTR_CVOID PEAssembly::GetLoadedMetadata(COUNT_T *pSize)
{
CONTRACT(PTR_CVOID)
{
@@ -493,9 +267,9 @@ PTR_CVOID PEFile::GetLoadedMetadata(COUNT_T *pSize)
}
CONTRACT_END;
- if (!HasLoadedIL()
- || !GetLoadedIL()->HasNTHeaders()
- || !GetLoadedIL()->HasCorHeader())
+ if (!HasLoadedPEImage()
+ || !GetLoadedLayout()->HasNTHeaders()
+ || !GetLoadedLayout()->HasCorHeader())
{
if (pSize != NULL)
*pSize = 0;
@@ -503,20 +277,19 @@ PTR_CVOID PEFile::GetLoadedMetadata(COUNT_T *pSize)
}
else
{
- RETURN GetLoadedIL()->GetMetadata(pSize);
+ RETURN GetLoadedLayout()->GetMetadata(pSize);
}
}
-TADDR PEFile::GetIL(RVA il)
+TADDR PEAssembly::GetIL(RVA il)
{
CONTRACT(TADDR)
{
INSTANCE_CHECK;
PRECONDITION(il != 0);
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
#ifndef DACCESS_COMPILE
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
#endif
POSTCONDITION(RETVAL != NULL);
THROWS;
@@ -527,8 +300,7 @@ TADDR PEFile::GetIL(RVA il)
CONTRACT_END;
PEImageLayout *image = NULL;
-
- image = GetLoadedIL();
+ image = GetLoadedLayout();
#ifndef DACCESS_COMPILE
// Verify that the IL blob is valid before giving it out
@@ -541,7 +313,7 @@ TADDR PEFile::GetIL(RVA il)
#ifndef DACCESS_COMPILE
-void PEFile::OpenImporter()
+void PEAssembly::OpenImporter()
{
CONTRACTL
{
@@ -557,7 +329,7 @@ void PEFile::OpenImporter()
ConvertMDInternalToReadWrite();
IMetaDataImport2 *pIMDImport = NULL;
- IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetMDImport(),
IID_IMetaDataImport2,
(void **)&pIMDImport));
@@ -566,7 +338,7 @@ void PEFile::OpenImporter()
pIMDImport->Release();
}
-void PEFile::ConvertMDInternalToReadWrite()
+void PEAssembly::ConvertMDInternalToReadWrite()
{
CONTRACTL
{
@@ -617,7 +389,6 @@ void PEFile::ConvertMDInternalToReadWrite()
// Swap the pointers in a thread safe manner. If the contents of *ppImport
// equals pOld then no other thread got here first, and the old contents are
// replaced with pNew. The old contents are returned.
- _ASSERTE(m_bHasPersistentMDImport);
if (FastInterlockCompareExchangePointer(&m_pMDImport, pNew, pOld) == pOld)
{
//if the debugger queries, it will now see that we have RW metadata
@@ -634,7 +405,7 @@ void PEFile::ConvertMDInternalToReadWrite()
}
}
-void PEFile::OpenMDImport_Unsafe()
+void PEAssembly::OpenMDImport()
{
CONTRACTL
{
@@ -649,23 +420,21 @@ void PEFile::OpenMDImport_Unsafe()
if (m_pMDImport != NULL)
return;
if (!IsDynamic()
- && GetILimage()->HasNTHeaders()
- && GetILimage()->HasCorHeader())
+ && GetPEImage()->HasNTHeaders()
+ && GetPEImage()->HasCorHeader())
{
- m_pMDImport=GetILimage()->GetMDImport();
+ m_pMDImport=GetPEImage()->GetMDImport();
}
else
{
ThrowHR(COR_E_BADIMAGEFORMAT);
}
- m_bHasPersistentMDImport=TRUE;
-
_ASSERTE(m_pMDImport);
m_pMDImport->AddRef();
}
-void PEFile::OpenEmitter()
+void PEAssembly::OpenEmitter()
{
CONTRACTL
{
@@ -681,7 +450,7 @@ void PEFile::OpenEmitter()
ConvertMDInternalToReadWrite();
IMetaDataEmit *pIMDEmit = NULL;
- IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetPersistentMDImport(),
+ IfFailThrow(GetMetaDataPublicInterfaceFromInternal((void*)GetMDImport(),
IID_IMetaDataEmit,
(void **)&pIMDEmit));
@@ -690,39 +459,6 @@ void PEFile::OpenEmitter()
pIMDEmit->Release();
}
-
-void PEFile::ReleaseMetadataInterfaces(BOOL bDestructor)
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(bDestructor||m_pMetadataLock->IsWriterLock());
- }
- CONTRACTL_END;
- _ASSERTE(bDestructor || !m_bHasPersistentMDImport);
-
- if (m_pImporter != NULL)
- {
- m_pImporter->Release();
- m_pImporter = NULL;
- }
- if (m_pEmitter != NULL)
- {
- m_pEmitter->Release();
- m_pEmitter = NULL;
- }
-
- if (m_pMDImport != NULL)
- {
- m_pMDImport->Release();
- m_pMDImport=NULL;
- }
-}
-
-
// ------------------------------------------------------------
// PE file access
// ------------------------------------------------------------
@@ -740,7 +476,7 @@ void PEFile::ReleaseMetadataInterfaces(BOOL bDestructor)
// Resource access
// ------------------------------------------------------------
-void PEFile::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInMemoryResource)
+void PEAssembly::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInMemoryResource)
{
CONTRACTL
{
@@ -756,10 +492,9 @@ void PEFile::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInM
// m_loadedImage is probably preferable, but this may be called by security
// before the image is loaded.
- EnsureImageOpened();
- PEImage* image = GetILimage();
+ PEImage* image = GetPEImage();
- PEImageLayoutHolder theImage(image->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED));
+ PEImageLayout* theImage = image->GetOrCreateLayout(PEImageLayout::LAYOUT_ANY);
if (!theImage->CheckResource(dwOffset))
ThrowHR(COR_E_BADIMAGEFORMAT);
@@ -774,10 +509,7 @@ void PEFile::GetEmbeddedResource(DWORD dwOffset, DWORD *cbResource, PBYTE *pbInM
// File loading
// ------------------------------------------------------------
-PEAssembly *
-PEFile::LoadAssembly(
- mdAssemblyRef kAssemblyRef,
- IMDInternalImport * pImport)
+PEAssembly* PEAssembly::LoadAssembly(mdAssemblyRef kAssemblyRef)
{
CONTRACT(PEAssembly *)
{
@@ -790,9 +522,7 @@ PEFile::LoadAssembly(
}
CONTRACT_END;
- if (pImport == NULL)
- pImport = GetPersistentMDImport();
-
+ IMDInternalImport* pImport = GetMDImport();
if (((TypeFromToken(kAssemblyRef) != mdtAssembly) &&
(TypeFromToken(kAssemblyRef) != mdtAssemblyRef)) ||
(!pImport->IsValidToken(kAssemblyRef)))
@@ -802,16 +532,16 @@ PEFile::LoadAssembly(
AssemblySpec spec;
- spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(GetAssembly()));
+ spec.InitializeSpec(kAssemblyRef, pImport, GetAppDomain()->FindAssembly(this));
RETURN GetAppDomain()->BindAssemblySpec(&spec, TRUE);
}
-BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
- PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef,
- LPCSTR *szFileName, DWORD *dwLocation,
- BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, AppDomain* pAppDomain)
+BOOL PEAssembly::GetResource(LPCSTR szName, DWORD *cbResource,
+ PBYTE *pbInMemoryResource, DomainAssembly** pAssemblyRef,
+ LPCSTR *szFileName, DWORD *dwLocation,
+ BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly, AppDomain* pAppDomain)
{
CONTRACTL
{
@@ -829,11 +559,11 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
DWORD dwOffset;
mdManifestResource mdResource;
Assembly* pAssembly = NULL;
- PEFile* pPEFile = NULL;
- ReleaseHolder pImport (GetMDImportWithRef());
+ PEAssembly* pPEAssembly = NULL;
+ IMDInternalImport* pImport = GetMDImport();
if (SUCCEEDED(pImport->FindManifestResourceByName(szName, &mdResource)))
{
- pPEFile = this;
+ pPEAssembly = this;
IfFailThrow(pImport->GetManifestResourceProps(
mdResource,
NULL, //&szName,
@@ -846,13 +576,13 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
if (fSkipRaiseResolveEvent || pAppDomain == NULL)
return FALSE;
- DomainAssembly* pParentAssembly = GetAppDomain()->FindAssembly(GetAssembly());
+ DomainAssembly* pParentAssembly = GetAppDomain()->FindAssembly(this);
pAssembly = pAppDomain->RaiseResourceResolveEvent(pParentAssembly, szName);
if (pAssembly == NULL)
return FALSE;
pDomainAssembly = pAssembly->GetDomainAssembly();
- pPEFile = pDomainAssembly->GetFile();
+ pPEAssembly = pDomainAssembly->GetPEAssembly();
if (FAILED(pAssembly->GetManifestImport()->FindManifestResourceByName(
szName,
@@ -868,7 +598,7 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
*dwLocation = *dwLocation | 2; // ResourceLocation.containedInAnotherAssembly
}
- IfFailThrow(pPEFile->GetPersistentMDImport()->GetManifestResourceProps(
+ IfFailThrow(pPEAssembly->GetMDImport()->GetManifestResourceProps(
mdResource,
NULL, //&szName,
&mdLinkRef,
@@ -884,7 +614,7 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
return FALSE;
AssemblySpec spec;
- spec.InitializeSpec(mdLinkRef, GetPersistentMDImport(), pDomainAssembly);
+ spec.InitializeSpec(mdLinkRef, GetMDImport(), pDomainAssembly);
pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED);
if (dwLocation) {
@@ -915,7 +645,7 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
return TRUE;
}
- pPEFile->GetEmbeddedResource(dwOffset, cbResource, pbInMemoryResource);
+ pPEAssembly->GetEmbeddedResource(dwOffset, cbResource, pbInMemoryResource);
return TRUE;
}
@@ -926,24 +656,23 @@ BOOL PEFile::GetResource(LPCSTR szName, DWORD *cbResource,
}
}
-void PEFile::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
+void PEAssembly::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
{
WRAPPER_NO_CONTRACT;
- if (IsResource() || IsDynamic())
+ _ASSERTE(pdwKind != NULL && pdwMachine != NULL);
+ if (IsDynamic())
{
- if (pdwKind)
- *pdwKind = 0;
- if (pdwMachine)
- *pdwMachine = 0;
+ *pdwKind = 0;
+ *pdwMachine = 0;
return;
}
- GetILimage()->GetPEKindAndMachine(pdwKind, pdwMachine);
+ GetPEImage()->GetPEKindAndMachine(pdwKind, pdwMachine);
return;
}
-ULONG PEFile::GetILImageTimeDateStamp()
+ULONG PEAssembly::GetPEImageTimeDateStamp()
{
CONTRACTL
{
@@ -953,62 +682,63 @@ ULONG PEFile::GetILImageTimeDateStamp()
}
CONTRACTL_END;
- return GetLoadedIL()->GetTimeDateStamp();
-}
-
-
-// ================================================================================
-// PEAssembly class - a PEFile which represents an assembly
-// ================================================================================
-
-// Statics initialization.
-/* static */
-void PEAssembly::Attach()
-{
- STANDARD_VM_CONTRACT;
+ return GetLoadedLayout()->GetTimeDateStamp();
}
#ifndef DACCESS_COMPILE
+
PEAssembly::PEAssembly(
BINDER_SPACE::Assembly* pBindResultInfo,
IMetaDataEmit* pEmit,
- PEFile *creator,
- BOOL system,
- PEImage * pPEImageIL /*= NULL*/,
+ PEAssembly *creator,
+ BOOL isSystem,
+ PEImage * pPEImage /*= NULL*/,
BINDER_SPACE::Assembly * pHostAssembly /*= NULL*/)
-
- : PEFile(pBindResultInfo ? pBindResultInfo->GetPEImage()
- : pPEImageIL),
- m_creator(clr::SafeAddRef(creator))
{
CONTRACTL
{
CONSTRUCTOR_CHECK;
PRECONDITION(CheckPointer(pEmit, NULL_OK));
PRECONDITION(CheckPointer(creator, NULL_OK));
- PRECONDITION(pBindResultInfo == NULL || pPEImageIL == NULL);
+ PRECONDITION(pBindResultInfo == NULL || pPEImage == NULL);
STANDARD_VM_CHECK;
}
CONTRACTL_END;
- m_flags |= PEFILE_ASSEMBLY;
- if (system)
- m_flags |= PEFILE_SYSTEM;
+ m_creator = clr::SafeAddRef(creator);
+#if _DEBUG
+ m_pDebugName = NULL;
+#endif
+ m_PEImage = NULL;
+ m_MDImportIsRW_Debugger_Use_Only = FALSE;
+ m_pMDImport = NULL;
+ m_pImporter = NULL;
+ m_pEmitter = NULL;
+ m_refCount = 1;
+ m_isSystem = isSystem;
+ m_pHostAssembly = nullptr;
+ m_pFallbackBinder = nullptr;
- // We require a mapping for the file.
- EnsureImageOpened();
+ pPEImage = pBindResultInfo ? pBindResultInfo->GetPEImage() : pPEImage;
+ if (pPEImage)
+ {
+ _ASSERTE(pPEImage->CheckUniqueInstance());
+ pPEImage->AddRef();
+
+ // We require a mapping for the file.
+ pPEImage->GetOrCreateLayout(PEImageLayout::LAYOUT_ANY);
+ m_PEImage = pPEImage;
+ }
// Open metadata eagerly to minimize failure windows
if (pEmit == NULL)
- OpenMDImport_Unsafe(); //constructor, cannot race with anything
+ OpenMDImport(); //constructor, cannot race with anything
else
{
- _ASSERTE(!m_bHasPersistentMDImport);
IfFailThrow(GetMetaDataInternalInterfaceFromPublic(pEmit, IID_IMDInternalImport,
(void **)&m_pMDImport));
m_pEmitter = pEmit;
pEmit->AddRef();
- m_bHasPersistentMDImport=TRUE;
m_MDImportIsRW_Debugger_Use_Only = TRUE;
}
@@ -1040,7 +770,7 @@ PEAssembly::PEAssembly(
}
#if _DEBUG
- GetCodeBaseOrName(m_debugName);
+ GetPathOrCodeBase(m_debugName);
m_debugName.Normalize();
m_pDebugName = m_debugName;
#endif
@@ -1058,7 +788,7 @@ PEAssembly *PEAssembly::Open(
PEAssembly * pPEAssembly = new PEAssembly(
nullptr, // BindResult
nullptr, // IMetaDataEmit
- pParent, // PEFile creator
+ pParent, // PEAssembly creator
FALSE, // isSystem
pPEImageIL,
pHostAssembly);
@@ -1082,6 +812,29 @@ PEAssembly::~PEAssembly()
if (m_creator != NULL)
m_creator->Release();
+ if (m_pImporter != NULL)
+ {
+ m_pImporter->Release();
+ m_pImporter = NULL;
+ }
+
+ if (m_pEmitter != NULL)
+ {
+ m_pEmitter->Release();
+ m_pEmitter = NULL;
+ }
+
+ if (m_pMDImport != NULL)
+ {
+ m_pMDImport->Release();
+ m_pMDImport = NULL;
+ }
+
+ if (m_PEImage != NULL)
+ m_PEImage->Release();
+
+ if (m_pHostAssembly != NULL)
+ m_pHostAssembly->Release();
}
/* static */
@@ -1126,12 +879,9 @@ PEAssembly *PEAssembly::DoOpenSystem()
RETURN new PEAssembly(pBoundAssembly, NULL, NULL, TRUE);
}
-PEAssembly* PEAssembly::Open(BINDER_SPACE::Assembly* pBindResult,
- BOOL isSystem)
+PEAssembly* PEAssembly::Open(BINDER_SPACE::Assembly* pBindResult)
{
-
- return new PEAssembly(pBindResult,NULL,NULL,isSystem);
-
+ return new PEAssembly(pBindResult,NULL,NULL, /*isSystem*/ false);
};
/* static */
@@ -1151,15 +901,12 @@ PEAssembly *PEAssembly::Create(PEAssembly *pParentAssembly,
// we have.)
SafeComHolder pEmit;
pAssemblyEmit->QueryInterface(IID_IMetaDataEmit, (void **)&pEmit);
- PEAssemblyHolder pFile(new PEAssembly(NULL, pEmit, pParentAssembly, FALSE));
- RETURN pFile.Extract();
+ RETURN new PEAssembly(NULL, pEmit, pParentAssembly, FALSE);
}
-
#endif // #ifndef DACCESS_COMPILE
-
#ifndef DACCESS_COMPILE
// ------------------------------------------------------------
@@ -1179,23 +926,23 @@ const SString &PEAssembly::GetEffectivePath()
}
CONTRACTL_END;
- PEAssembly *pAssembly = this;
+ PEAssembly* pPEAssembly = this;
- while (pAssembly->m_identity == NULL
- || pAssembly->m_identity->GetPath().IsEmpty())
+ while (pPEAssembly->m_PEImage == NULL
+ || pPEAssembly->m_PEImage->GetPath().IsEmpty())
{
- if (pAssembly->m_creator)
- pAssembly = pAssembly->m_creator->GetAssembly();
+ if (pPEAssembly->m_creator)
+ pPEAssembly = pPEAssembly->m_creator;
else // Unmanaged exe which loads byte[]/IStream assemblies
return SString::Empty();
}
- return pAssembly->m_identity->GetPath();
+ return pPEAssembly->m_PEImage->GetPath();
}
// Codebase is the fusion codebase or path for the assembly. It is in URL format.
-// Note this may be obtained from the parent PEFile if we don't have a path or fusion
+// Note this may be obtained from the parent PEAssembly if we don't have a path or fusion
// assembly.
// Returns false if the assembly was loaded from a bundle, true otherwise
BOOL PEAssembly::GetCodeBase(SString &result)
@@ -1210,13 +957,14 @@ BOOL PEAssembly::GetCodeBase(SString &result)
}
CONTRACTL_END;
- auto ilImage = GetILimage();
- if (ilImage == nullptr || !ilImage->IsInBundle())
+ PEImage* ilImage = GetPEImage();
+ if (ilImage == NULL || !ilImage->IsInBundle())
{
// All other cases use the file path.
result.Set(GetEffectivePath());
if (!result.IsEmpty())
PathToUrl(result);
+
return TRUE;
}
else
@@ -1322,7 +1070,7 @@ BOOL PEAssembly::FindLastPathSeparator(const SString &path, SString::Iterator &i
// Metadata access
// ------------------------------------------------------------
-HRESULT PEFile::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision)
+HRESULT PEAssembly::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision)
{
CONTRACTL
{
@@ -1337,19 +1085,11 @@ HRESULT PEFile::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHOR
}
CONTRACTL_END;
- AssemblyMetaDataInternal md;
+ _ASSERTE(GetMDImport()->IsValidToken(TokenFromRid(1, mdtAssembly)));
+
HRESULT hr = S_OK;;
- if (m_bHasPersistentMDImport)
- {
- _ASSERTE(GetPersistentMDImport()->IsValidToken(TokenFromRid(1, mdtAssembly)));
- IfFailRet(GetPersistentMDImport()->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
- }
- else
- {
- ReleaseHolder pImport(GetMDImportWithRef());
- _ASSERTE(pImport->IsValidToken(TokenFromRid(1, mdtAssembly)));
- IfFailRet(pImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
- }
+ AssemblyMetaDataInternal md;
+ IfFailRet(GetMDImport()->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, &md, NULL));
if (pMajor != NULL)
*pMajor = md.usMajorVersion;
@@ -1360,55 +1100,30 @@ HRESULT PEFile::GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHOR
if (pRevision != NULL)
*pRevision = md.usRevisionNumber;
- return hr;
-}
-
-
-
-void PEFile::EnsureImageOpened()
-{
- WRAPPER_NO_CONTRACT;
- if (IsDynamic())
- return;
-
- GetILimage()->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
+ return S_OK;
}
#endif // #ifndef DACCESS_COMPILE
#ifdef DACCESS_COMPILE
-void
-PEFile::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+void PEAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- // sizeof(PEFile) == 0xb8
DAC_ENUM_VTHIS();
- EMEM_OUT(("MEM: %p PEFile\n", dac_cast(this)));
+ EMEM_OUT(("MEM: %p PEAssembly\n", dac_cast(this)));
#ifdef _DEBUG
// Not a big deal if it's NULL or fails.
m_debugName.EnumMemoryRegions(flags);
#endif
- if (m_identity.IsValid())
+ if (m_PEImage.IsValid())
{
- m_identity->EnumMemoryRegions(flags);
+ m_PEImage->EnumMemoryRegions(flags);
}
- if (GetILimage().IsValid())
- {
- GetILimage()->EnumMemoryRegions(flags);
- }
-}
-
-void
-PEAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
-{
- WRAPPER_NO_CONTRACT;
-
- PEFile::EnumMemoryRegions(flags);
if (m_creator.IsValid())
{
@@ -1426,7 +1141,7 @@ PEAssembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
// It can return an empty if the name isn't available or the object isn't initialized
// enough to get a name, but it mustn't crash.
//-------------------------------------------------------------------------------
-LPCWSTR PEFile::GetPathForErrorMessages()
+LPCWSTR PEAssembly::GetPathForErrorMessages()
{
CONTRACTL
{
@@ -1439,7 +1154,7 @@ LPCWSTR PEFile::GetPathForErrorMessages()
if (!IsDynamic())
{
- return m_identity->GetPathForErrorMessages();
+ return m_PEImage->GetPathForErrorMessages();
}
else
{
@@ -1449,7 +1164,7 @@ LPCWSTR PEFile::GetPathForErrorMessages()
#ifdef DACCESS_COMPILE
-TADDR PEFile::GetMDInternalRWAddress()
+TADDR PEAssembly::GetMDInternalRWAddress()
{
if (!m_MDImportIsRW_Debugger_Use_Only)
return 0;
@@ -1467,13 +1182,13 @@ TADDR PEFile::GetMDInternalRWAddress()
// 3) ASSUMPTION: We are assuming that no pointer adjustment is required to convert between
// IMDInternalImport*, IMDInternalImportENC* and MDInternalRW*. Ideally I was hoping to do this with a
// static_cast<> but the compiler complains that the ENC<->RW is an unrelated conversion.
- return (TADDR) m_pMDImport_UseAccessor;
+ return (TADDR)m_pMDImport_UseAccessor;
}
}
#endif
-// Returns the AssemblyBinder* instance associated with the PEFile
-PTR_AssemblyBinder PEFile::GetAssemblyBinder()
+// Returns the AssemblyBinder* instance associated with the PEAssembly
+PTR_AssemblyBinder PEAssembly::GetAssemblyBinder()
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/coreclr/vm/pefile.h b/src/coreclr/vm/peassembly.h
similarity index 57%
rename from src/coreclr/vm/pefile.h
rename to src/coreclr/vm/peassembly.h
index 317c9c544228f..adc19df11bc9b 100644
--- a/src/coreclr/vm/pefile.h
+++ b/src/coreclr/vm/peassembly.h
@@ -1,14 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// --------------------------------------------------------------------------------
-// PEFile.h
+// PEAssembly.h
//
// --------------------------------------------------------------------------------
-#ifndef PEFILE_H_
-#define PEFILE_H_
+#ifndef PEASSEMBLY_H_
+#define PEASSEMBLY_H_
// --------------------------------------------------------------------------------
// Required headers
@@ -41,7 +41,6 @@
class Module;
class EditAndContinueModule;
-class PEFile;
class PEAssembly;
class SimpleRWLock;
@@ -52,23 +51,25 @@ typedef VPTR(PEAssembly) PTR_PEAssembly;
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
-// A PEFile is an input to the CLR loader. It is produced as a result of
+// A PEAssembly is an input to the CLR loader. It is produced as a result of
// binding, usually through fusion (although there are a few less common methods to
// obtain one which do not go through fusion, e.g. IJW loads)
//
-// Although a PEFile is usually a disk based PE file (hence the name), it is not
+// Although a PEAssembly is usually a disk based PE file, it is not
// always the case. Thus it is a conscious decision to not export access to the PE
// file directly; rather the specific information required should be provided via
// individual query API.
//
-// There are multiple "flavors" of PEFiles:
+// There are multiple "flavors" of PEAssemblies:
//
// 1. HMODULE - these PE Files are loaded in response to "spontaneous" OS callbacks.
// These should only occur for .exe main modules and IJW dlls loaded via LoadLibrary
// or static imports in umnanaged code.
+// These get their PEImage loaded directly in PEImage::LoadImage(HMODULE hMod)
//
-// 2. Fusion loads - these are the most common case. A path is obtained from fusion and
-// the result is loaded via PEImage.
+// 2. Assemblies loaded directly or indirectly by the managed code - these are the most
+// common case. A path is obtained from assembly binding and the result is loaded
+// via PEImage:
// a. Display name loads - these are metadata-based binds
// b. Path loads - these are loaded from an explicit path
//
@@ -78,19 +79,14 @@ typedef VPTR(PEAssembly) PTR_PEAssembly;
// for reflection-based modules.
//
// See also file:..\inc\corhdr.h#ManagedHeader for more on the format of managed images.
-// See code:Module for more on modules
// --------------------------------------------------------------------------------
-typedef VPTR(class PEFile) PTR_PEFile;
-
-typedef ReleaseHolder IMDInternalImportHolder;
-
-class PEFile
+class PEAssembly final
{
// ------------------------------------------------------------
// SOS support
// ------------------------------------------------------------
- VPTR_BASE_CONCRETE_VTABLE_CLASS(PEFile)
+ VPTR_BASE_CONCRETE_VTABLE_CLASS(PEAssembly)
public:
@@ -109,54 +105,15 @@ class PEFile
CHECK Invariant();
#endif
-private:
- // ------------------------------------------------------------
- // Loader access API
- // ------------------------------------------------------------
-
- friend class DomainFile;
-
-public:
- void LoadLibrary(BOOL allowNativeSkip = TRUE);
-
-
-private:
- // For use inside LoadLibrary callback
- void SetLoadedHMODULE(HMODULE hMod);
-
- // DO NOT USE !!! this is to be removed when we move to new fusion binding API
- friend class DomainAssembly;
-
- // Helper for creating metadata for CreateDynamic
- friend class Assembly;
- friend class COMDynamicWrite;
- friend class AssemblyNative;
- static void DefineEmitScope(
- GUID iid,
- void **ppEmit);
-
-protected:
- IMDInternalImportHolder GetMDImport();
-
-public:
- // ------------------------------------------------------------
- // Generic PEFile - can be used to access metadata
- // ------------------------------------------------------------
-
- static PEFile *Open(PEImage *image);
-
// ------------------------------------------------------------
// Identity
// ------------------------------------------------------------
#ifndef DACCESS_COMPILE
- BOOL Equals(PEFile *pFile);
+ BOOL Equals(PEAssembly *pPEAssembly);
BOOL Equals(PEImage *pImage);
#endif // DACCESS_COMPILE
-
- void GetMVID(GUID *pMvid);
-
// ------------------------------------------------------------
// Descriptive strings
// ------------------------------------------------------------
@@ -170,8 +127,22 @@ class PEFile
const SString &GetModuleFileNameHint();
#endif // DACCESS_COMPILE
+ LPCWSTR GetPathForErrorMessages();
+
+ // This returns a non-empty path representing the source of the assembly; it may
+ // be the parent assembly for dynamic or memory assemblies
+ const SString& GetEffectivePath();
+
+ // Codebase is the fusion codebase or path for the assembly. It is in URL format.
+ // Note this may be obtained from the parent PEAssembly if we don't have a path or fusion
+ // assembly.
+ BOOL GetCodeBase(SString& result);
+
// Full name is the most descriptive name available (path, codebase, or name as appropriate)
- void GetCodeBaseOrName(SString &result);
+ void GetPathOrCodeBase(SString& result);
+
+ // Display name is the fusion binding name for an assembly
+ void GetDisplayName(SString& result, DWORD flags = 0);
#ifdef LOGGING
// This is useful for log messages
@@ -182,68 +153,49 @@ class PEFile
// Checks
// ------------------------------------------------------------
- CHECK CheckLoaded(BOOL allowNativeSkip = TRUE);
void ValidateForExecution();
BOOL IsMarkedAsNoPlatform();
-
// ------------------------------------------------------------
// Classification
// ------------------------------------------------------------
- BOOL IsAssembly() const;
- PTR_PEAssembly AsAssembly();
BOOL IsSystem() const;
BOOL IsDynamic() const;
- BOOL IsResource() const;
- BOOL IsIStream() const;
- // Returns self (if assembly) or containing assembly (if module)
- PEAssembly *GetAssembly() const;
// ------------------------------------------------------------
// Metadata access
// ------------------------------------------------------------
- BOOL HasMetadata();
-
- IMDInternalImport *GetPersistentMDImport();
- IMDInternalImport *GetMDImportWithRef();
- void MakeMDImportPersistent() {m_bHasPersistentMDImport=TRUE;};
+ IMDInternalImport *GetMDImport();
#ifndef DACCESS_COMPILE
IMetaDataEmit *GetEmitter();
- IMetaDataAssemblyEmit *GetAssemblyEmitter();
IMetaDataImport2 *GetRWImporter();
- IMetaDataAssemblyImport *GetAssemblyImporter();
#else
TADDR GetMDInternalRWAddress();
#endif // DACCESS_COMPILE
+ void ConvertMDInternalToReadWrite();
+
+ void GetMVID(GUID* pMvid);
+ ULONG GetHashAlgId();
+ HRESULT GetVersion(USHORT* pMajor, USHORT* pMinor, USHORT* pBuild, USHORT* pRevision);
+ BOOL IsStrongNamed();
LPCUTF8 GetSimpleName();
HRESULT GetScopeName(LPCUTF8 * pszName);
- BOOL IsStrongNameVerified();
- BOOL IsStrongNamed();
const void *GetPublicKey(DWORD *pcbPK);
- ULONG GetHashAlgId();
- HRESULT GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision);
LPCSTR GetLocale();
DWORD GetFlags();
- HRESULT GetFlagsNoTrigger(DWORD * pdwFlags);
+
// ------------------------------------------------------------
// PE file access
// ------------------------------------------------------------
- BOOL IsIbcOptimized();
BOOL IsReadyToRun();
- WORD GetSubsystem();
- mdToken GetEntryPointToken(
-#ifdef _DEBUG
- BOOL bAssumeLoaded = FALSE
-#endif //_DEBUG
- );
- BOOL IsILOnly();
- BOOL IsDll();
+ mdToken GetEntryPointToken();
+ BOOL IsILOnly();
TADDR GetIL(RVA il);
PTR_VOID GetRvaField(RVA field);
@@ -266,15 +218,14 @@ class PEFile
LPCSTR *szFileName, DWORD *dwLocation,
BOOL fSkipRaiseResolveEvent, DomainAssembly* pDomainAssembly,
AppDomain* pAppDomain);
+
#ifndef DACCESS_COMPILE
PTR_CVOID GetMetadata(COUNT_T *pSize);
#endif
- PTR_CVOID GetLoadedMetadata(COUNT_T *pSize);
+ PTR_CVOID GetLoadedMetadata(COUNT_T *pSize);
void GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine);
-
- ULONG GetILImageTimeDateStamp();
-
+ ULONG GetPEImageTimeDateStamp();
// ------------------------------------------------------------
// Image memory access
@@ -288,32 +239,54 @@ class PEFile
// in the no-IL image case.
// ------------------------------------------------------------
+ BOOL HasPEImage()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_PEImage != NULL;
+ }
+
+ PEImage* GetPEImage()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_PEImage;
+ }
+
+ void EnsureLoaded();
+
+ BOOL HasLoadedPEImage()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return HasPEImage() && GetPEImage()->HasLoadedLayout();
+ }
+
+ PTR_PEImageLayout GetLoadedLayout()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+
+ _ASSERTE(HasPEImage());
+ return GetPEImage()->GetLoadedLayout();
+ };
+
+ BOOL IsLoaded()
+ {
+ return IsDynamic() || HasLoadedPEImage();
+ }
+
+ BOOL IsPtrInPEImage(PTR_CVOID data);
+
// For IJW purposes only - this asserts that we have an IJW image.
HMODULE GetIJWBase();
// The debugger can tolerate a null value here for native only loading cases
- PTR_VOID GetDebuggerContents(COUNT_T *pSize = NULL);
+ PTR_VOID GetDebuggerContents(COUNT_T* pSize = NULL);
#ifndef DACCESS_COMPILE
// Returns the IL image range; may force a LoadLibrary
- const void *GetManagedFileContents(COUNT_T *pSize = NULL);
+ const void* GetManagedFileContents(COUNT_T* pSize = NULL);
#endif // DACCESS_COMPILE
- PTR_CVOID GetLoadedImageContents(COUNT_T *pSize = NULL);
-
- // ------------------------------------------------------------
- // Native image access
- // ------------------------------------------------------------
-
- // Does the loader support using a native image for this file?
- // Some implementation restrictions prevent native images from being used
- // in some cases.
- PTR_PEImageLayout GetLoaded();
- PTR_PEImageLayout GetLoadedIL();
- IStream * GetPdbStream();
- void ClearPdbStream();
- BOOL IsLoaded(BOOL bAllowNativeSkip=TRUE) ;
- BOOL IsPtrInILImage(PTR_CVOID data);
+ PTR_CVOID GetLoadedImageContents(COUNT_T* pSize = NULL);
// ------------------------------------------------------------
// Resource access
@@ -325,141 +298,18 @@ class PEFile
// File loading
// ------------------------------------------------------------
- PEAssembly * LoadAssembly(
- mdAssemblyRef kAssemblyRef,
- IMDInternalImport * pImport = NULL);
-
-protected:
- // ------------------------------------------------------------
- // Internal constants
- // ------------------------------------------------------------
-
- enum
- {
- PEFILE_SYSTEM = 0x01,
- PEFILE_ASSEMBLY = 0x02,
- };
-
- // ------------------------------------------------------------
- // Internal routines
- // ------------------------------------------------------------
-
-#ifndef DACCESS_COMPILE
- PEFile(PEImage *image);
- virtual ~PEFile();
-#else
- virtual ~PEFile() {}
-#endif
-
- void OpenMDImport();
- void OpenMDImport_Unsafe();
- void OpenImporter();
- void OpenEmitter();
-
- void ReleaseMetadataInterfaces(BOOL bDestructor);
-
-
- friend class Module;
-
-#ifndef DACCESS_COMPILE
- void EnsureImageOpened();
-#endif // DACCESS_COMPILE
-
- friend class ClrDataAccess;
+ PEAssembly * LoadAssembly(mdAssemblyRef kAssemblyRef);
// ------------------------------------------------------------
- // Instance fields
+ // Assembly Binder and host assembly (BINDER_SPACE::Assembly)
// ------------------------------------------------------------
-#ifdef _DEBUG
- LPCWSTR m_pDebugName;
- SString m_debugName;
-#endif
-
- // Identity image
- PTR_PEImage m_identity;
- // IL image, NULL if we didn't need to open the file
- PTR_PEImage m_openedILimage;
- // This flag is not updated atomically with m_pMDImport. Its fine for debugger usage
- // but don't rely on it in the runtime. In runtime try QI'ing the m_pMDImport for
- // IID_IMDInternalImportENC
- BOOL m_MDImportIsRW_Debugger_Use_Only;
- Volatile m_bHasPersistentMDImport;
-
-#ifndef DACCESS_COMPILE
- IMDInternalImport *m_pMDImport;
-#else
- IMDInternalImport *m_pMDImport_UseAccessor;
-#endif
- IMetaDataImport2 *m_pImporter;
- IMetaDataEmit *m_pEmitter;
- SimpleRWLock *m_pMetadataLock;
- Volatile m_refCount;
- int m_flags;
-
-public:
-
- PTR_PEImage GetILimage()
- {
- CONTRACTL
- {
- THROWS;
- MODE_ANY;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-#ifndef DACCESS_COMPILE
- if (m_openedILimage == NULL && m_identity != NULL)
- {
- PEImage* pOpenedILimage;
- m_identity->Clone(MDInternalImport_Default,&pOpenedILimage);
- if (InterlockedCompareExchangeT(&m_openedILimage,pOpenedILimage,NULL) != NULL)
- pOpenedILimage->Release();
- }
-#endif
- return m_openedILimage;
- }
-
- PEImage *GetOpenedILimage()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- _ASSERTE(HasOpenedILimage());
- return m_openedILimage;
- }
-
-
- BOOL HasOpenedILimage()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return m_openedILimage != NULL;
-
- }
-
- BOOL HasLoadedIL()
+ bool HasHostAssembly()
{
- LIMITED_METHOD_DAC_CONTRACT;
- return HasOpenedILimage() && GetOpenedILimage()->HasLoadedLayout();
+ STATIC_CONTRACT_WRAPPER;
+ return GetHostAssembly() != NULL;
}
- LPCWSTR GetPathForErrorMessages();
-
- static PEFile* Dummy();
-
- void ConvertMDInternalToReadWrite();
-
-protected:
- PTR_BINDER_SPACE_Assembly m_pHostAssembly;
-
- // For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder.
- // An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies,
- // we need to ensure they are loaded in appropriate load context.
- //
- // To enable this, we maintain a concept of "FallbackBinder", which will be set to the Binder of the
- // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback
- // load context would be propagated to the assembly being dynamically generated.
- PTR_AssemblyBinder m_pFallbackBinder;
-
-public:
// Returns a non-AddRef'ed BINDER_SPACE::Assembly*
PTR_BINDER_SPACE_Assembly GetHostAssembly()
{
@@ -467,8 +317,9 @@ class PEFile
return m_pHostAssembly;
}
- // Returns the AssemblyBinder* instance associated with the PEFile
- // which owns the context into which the current PEFile was loaded.
+ // Returns the AssemblyBinder* instance associated with the PEAssembly
+ // which owns the context into which the current PEAssembly was loaded.
+ // For Dynamic assemblies this is the fallback binder.
PTR_AssemblyBinder GetAssemblyBinder();
#ifndef DACCESS_COMPILE
@@ -480,8 +331,7 @@ class PEFile
#endif //!DACCESS_COMPILE
- bool HasHostAssembly()
- { STATIC_CONTRACT_WRAPPER; return GetHostAssembly() != nullptr; }
+ ULONG HashIdentity();
PTR_AssemblyBinder GetFallbackBinder()
{
@@ -489,111 +339,122 @@ class PEFile
return m_pFallbackBinder;
}
-}; // class PEFile
-
-
-class PEAssembly : public PEFile
-{
- VPTR_VTABLE_CLASS(PEAssembly, PEFile)
- public:
// ------------------------------------------------------------
- // Statics initialization.
- // ------------------------------------------------------------
- static
- void Attach();
-
- // ------------------------------------------------------------
- // Public API
+ // Creation entry points
// ------------------------------------------------------------
// CoreCLR's PrivBinder PEAssembly creation entrypoint
- static PEAssembly * Open(
- PEAssembly * pParent,
- PEImage * pPEImageIL,
- BINDER_SPACE::Assembly * pHostAssembly);
+ static PEAssembly* Open(
+ PEAssembly* pParent,
+ PEImage* pPEImageIL,
+ BINDER_SPACE::Assembly* pHostAssembly);
// This opens the canonical System.Private.CoreLib.dll
- static PEAssembly *OpenSystem();
-#ifdef DACCESS_COMPILE
- virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
-#endif
+ static PEAssembly* OpenSystem();
- static PEAssembly *Open(
- BINDER_SPACE::Assembly* pBindResult,
- BOOL isSystem);
+ static PEAssembly* Open(BINDER_SPACE::Assembly* pBindResult);
- static PEAssembly *Create(
- PEAssembly *pParentAssembly,
- IMetaDataAssemblyEmit *pEmit);
+ static PEAssembly* Create(
+ PEAssembly* pParentAssembly,
+ IMetaDataAssemblyEmit* pEmit);
- private:
- // Private helpers for crufty exception handling reasons
- static PEAssembly *DoOpenSystem();
+ // ------------------------------------------------------------
+ // Utility functions
+ // ------------------------------------------------------------
- public:
+ static void PathToUrl(SString& string);
+ static void UrlToPath(SString& string);
+ static BOOL FindLastPathSeparator(const SString& path, SString::Iterator& i);
+private:
// ------------------------------------------------------------
- // binding & source
+ // Loader access API
// ------------------------------------------------------------
- ULONG HashIdentity();
+ // Private helper for crufty exception handling reasons
+ static PEAssembly* DoOpenSystem();
// ------------------------------------------------------------
- // Descriptive strings
+ // Internal routines
// ------------------------------------------------------------
- // This returns a non-empty path representing the source of the assembly; it may
- // be the parent assembly for dynamic or memory assemblies
- const SString &GetEffectivePath();
+#ifdef DACCESS_COMPILE
+ // just to make the DAC and GCC happy.
+ virtual ~PEAssembly() {};
+ PEAssembly() = default;
+#else
+ PEAssembly(
+ BINDER_SPACE::Assembly* pBindResultInfo,
+ IMetaDataEmit* pEmit,
+ PEAssembly* creator,
+ BOOL isSystem,
+ PEImage* pPEImageIL = NULL,
+ BINDER_SPACE::Assembly* pHostAssembly = NULL
+ );
- // Codebase is the fusion codebase or path for the assembly. It is in URL format.
- // Note this may be obtained from the parent PEFile if we don't have a path or fusion
- // assembly.
- BOOL GetCodeBase(SString &result);
+ virtual ~PEAssembly();
+#endif
- // Display name is the fusion binding name for an assembly
- void GetDisplayName(SString &result, DWORD flags = 0);
+ void OpenMDImport();
+ void OpenImporter();
+ void OpenEmitter();
- // ------------------------------------------------------------
- // Metadata access
- // ------------------------------------------------------------
+private:
- LPCUTF8 GetSimpleName();
+ // ------------------------------------------------------------
+ // Instance fields
+ // ------------------------------------------------------------
- // ------------------------------------------------------------
- // Utility functions
- // ------------------------------------------------------------
+#ifdef _DEBUG
+ LPCWSTR m_pDebugName;
+ SString m_debugName;
+#endif
- static void PathToUrl(SString &string);
- static void UrlToPath(SString &string);
- static BOOL FindLastPathSeparator(const SString &path, SString::Iterator &i);
+ // IL image, NULL if dynamic
+ PTR_PEImage m_PEImage;
- protected:
+ PTR_PEAssembly m_creator;
+ // This flag is not updated atomically with m_pMDImport. Its fine for debugger usage
+ // but don't rely on it in the runtime. In runtime try QI'ing the m_pMDImport for
+ // IID_IMDInternalImportENC
+ BOOL m_MDImportIsRW_Debugger_Use_Only;
+ union
+ {
#ifndef DACCESS_COMPILE
- PEAssembly(
- BINDER_SPACE::Assembly* pBindResultInfo,
- IMetaDataEmit *pEmit,
- PEFile *creator,
- BOOL system,
- PEImage * pPEImageIL = NULL,
- BINDER_SPACE::Assembly * pHostAssembly = NULL
- );
- virtual ~PEAssembly();
+ IMDInternalImport* m_pMDImport;
+#else
+ // NB: m_pMDImport_UseAccessor appears to be never assigned a value, but its purpose is just
+ // to be a placeholder that has the same type and offset as m_pMDImport.
+ //
+ // The field has a different name so it would be an error to use directly.
+ // Only GetMDInternalRWAddress is supposed to use it via (TADDR)m_pMDImport_UseAccessor,
+ // which at that point will match the m_pMDImport on the debuggee side.
+ // See more scary comments in GetMDInternalRWAddress.
+ IMDInternalImport* m_pMDImport_UseAccessor;
#endif
+ };
- private:
- // ------------------------------------------------------------
- // Instance fields
- // ------------------------------------------------------------
+ IMetaDataImport2* m_pImporter;
+ IMetaDataEmit* m_pEmitter;
- PTR_PEFile m_creator;
-};
+ Volatile m_refCount;
+ bool m_isSystem;
+ PTR_BINDER_SPACE_Assembly m_pHostAssembly;
+
+ // For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder.
+ // An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies,
+ // we need to ensure they are loaded in appropriate load context.
+ //
+ // To enable this, we maintain a concept of "FallbackBinder", which will be set to the Binder of the
+ // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback
+ // load context would be propagated to the assembly being dynamically generated.
+ PTR_AssemblyBinder m_pFallbackBinder;
-typedef ReleaseHolder PEFileHolder;
+}; // class PEAssembly
typedef ReleaseHolder PEAssemblyHolder;
-#endif // PEFILE_H_
+#endif // PEASSEMBLY_H_
diff --git a/src/coreclr/vm/pefile.inl b/src/coreclr/vm/peassembly.inl
similarity index 56%
rename from src/coreclr/vm/pefile.inl
rename to src/coreclr/vm/peassembly.inl
index e00136064bc1e..42102f13a05da 100644
--- a/src/coreclr/vm/pefile.inl
+++ b/src/coreclr/vm/peassembly.inl
@@ -1,13 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// --------------------------------------------------------------------------------
-// PEFile.inl
+// PEAssembly.inl
//
// --------------------------------------------------------------------------------
-#ifndef PEFILE_INL_
-#define PEFILE_INL_
+#ifndef PEASSEMBLY_INL_
+#define PEASSEMBLY_INL_
#include "check.h"
#include "simplerwlock.hpp"
@@ -15,7 +15,7 @@
#include "peimagelayout.inl"
#if CHECK_INVARIANTS
-inline CHECK PEFile::Invariant()
+inline CHECK PEAssembly::Invariant()
{
CONTRACT_CHECK
{
@@ -29,14 +29,12 @@ inline CHECK PEFile::Invariant()
if (IsDynamic())
{
// dynamic module case
- CHECK(m_openedILimage == NULL);
+ CHECK(m_PEImage == NULL);
CHECK(CheckPointer(m_pEmitter));
}
else
{
- // If m_image is null, then we should have a native image. However, this is not valid initially
- // during construction. We should find a way to assert this.
- CHECK(CheckPointer((PEImage*) m_openedILimage, NULL_OK));
+ CHECK(CheckPointer((PEImage*)m_PEImage));
}
CHECK_OK;
}
@@ -46,7 +44,7 @@ inline CHECK PEFile::Invariant()
// AddRef/Release
// ------------------------------------------------------------
-inline ULONG PEFile::AddRef()
+inline ULONG PEAssembly::AddRef()
{
CONTRACTL
{
@@ -61,7 +59,7 @@ inline ULONG PEFile::AddRef()
return FastInterlockIncrement(&m_refCount);
}
-inline ULONG PEFile::Release()
+inline ULONG PEAssembly::Release()
{
CONTRACT(COUNT_T)
{
@@ -88,7 +86,7 @@ inline ULONG PEAssembly::HashIdentity()
{
CONTRACTL
{
- PRECONDITION(CheckPointer(m_identity));
+ PRECONDITION(CheckPointer(m_PEImage));
MODE_ANY;
THROWS;
GC_TRIGGERS;
@@ -97,7 +95,7 @@ inline ULONG PEAssembly::HashIdentity()
return m_pHostAssembly->GetAssemblyName()->Hash(BINDER_SPACE::AssemblyName::INCLUDE_VERSION);
}
-inline void PEFile::ValidateForExecution()
+inline void PEAssembly::ValidateForExecution()
{
CONTRACTL
{
@@ -110,7 +108,7 @@ inline void PEFile::ValidateForExecution()
//
// Ensure reference assemblies are not loaded for execution
//
- ReleaseHolder mdImport(this->GetMDImportWithRef());
+ IMDInternalImport* mdImport = GetMDImport();
if (mdImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly),
g_ReferenceAssemblyAttribute,
NULL,
@@ -121,7 +119,7 @@ inline void PEFile::ValidateForExecution()
//
// Ensure platform is valid for execution
//
- if (!IsDynamic() && !IsResource())
+ if (!IsDynamic())
{
if (IsMarkedAsNoPlatform())
{
@@ -131,14 +129,14 @@ inline void PEFile::ValidateForExecution()
}
-inline BOOL PEFile::IsMarkedAsNoPlatform()
+inline BOOL PEAssembly::IsMarkedAsNoPlatform()
{
WRAPPER_NO_CONTRACT;
return (IsAfPA_NoPlatform(GetFlags()));
}
-inline void PEFile::GetMVID(GUID *pMvid)
+inline void PEAssembly::GetMVID(GUID *pMvid)
{
CONTRACTL
{
@@ -149,14 +147,14 @@ inline void PEFile::GetMVID(GUID *pMvid)
}
CONTRACTL_END;
- IfFailThrow(GetPersistentMDImport()->GetScopeProps(NULL, pMvid));
+ IfFailThrow(GetMDImport()->GetScopeProps(NULL, pMvid));
}
// ------------------------------------------------------------
// Descriptive strings
// ------------------------------------------------------------
-inline const SString& PEFile::GetPath()
+inline const SString& PEAssembly::GetPath()
{
CONTRACTL
{
@@ -169,17 +167,18 @@ inline const SString& PEFile::GetPath()
}
CONTRACTL_END;
- if (IsDynamic() || m_identity->IsInBundle ())
+ if (IsDynamic() || m_PEImage->IsInBundle ())
{
return SString::Empty();
}
- return m_identity->GetPath();
+
+ return m_PEImage->GetPath();
}
//
// Returns the identity path even for single-file/bundled apps.
//
-inline const SString& PEFile::GetIdentityPath()
+inline const SString& PEAssembly::GetIdentityPath()
{
CONTRACTL
{
@@ -192,15 +191,16 @@ inline const SString& PEFile::GetIdentityPath()
}
CONTRACTL_END;
- if (m_identity == nullptr)
+ if (m_PEImage == nullptr)
{
return SString::Empty();
}
- return m_identity->GetPath();
+
+ return m_PEImage->GetPath();
}
#ifdef DACCESS_COMPILE
-inline const SString &PEFile::GetModuleFileNameHint()
+inline const SString &PEAssembly::GetModuleFileNameHint()
{
CONTRACTL
{
@@ -216,12 +216,12 @@ inline const SString &PEFile::GetModuleFileNameHint()
return SString::Empty();
}
else
- return m_identity->GetModuleFileNameHintForDAC();
+ return m_PEImage->GetModuleFileNameHintForDAC();
}
#endif // DACCESS_COMPILE
#ifdef LOGGING
-inline LPCWSTR PEFile::GetDebugName()
+inline LPCWSTR PEAssembly::GetDebugName()
{
CONTRACTL
{
@@ -245,108 +245,29 @@ inline LPCWSTR PEFile::GetDebugName()
// Classification
// ------------------------------------------------------------
-inline BOOL PEFile::IsAssembly() const
-{
- LIMITED_METHOD_DAC_CONTRACT;
-
- return (m_flags & PEFILE_ASSEMBLY) != 0;
-}
-
-inline PTR_PEAssembly PEFile::AsAssembly()
-{
- LIMITED_METHOD_DAC_CONTRACT;
-
- if (IsAssembly())
- return dac_cast(this);
- else
- return dac_cast(nullptr);
-}
-
-inline BOOL PEFile::IsSystem() const
+inline BOOL PEAssembly::IsSystem() const
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
- return (m_flags & PEFILE_SYSTEM) != 0;
+ return m_isSystem;
}
-inline BOOL PEFile::IsDynamic() const
+inline BOOL PEAssembly::IsDynamic() const
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
- return m_identity == NULL;
-}
-
-inline BOOL PEFile::IsResource() const
-{
- WRAPPER_NO_CONTRACT;
- SUPPORTS_DAC;
-
- return FALSE;
-}
-
-inline BOOL PEFile::IsIStream() const
-{
- LIMITED_METHOD_CONTRACT;
-
- return FALSE;
-}
-
-inline PEAssembly *PEFile::GetAssembly() const
-{
- WRAPPER_NO_CONTRACT;
- _ASSERTE(IsAssembly());
- return dac_cast(this);
+ return m_PEImage == NULL;
}
// ------------------------------------------------------------
// Metadata access
// ------------------------------------------------------------
-
-inline BOOL PEFile::HasMetadata()
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
- return !IsResource();
-}
-
-inline IMDInternalImportHolder PEFile::GetMDImport()
+inline IMDInternalImport* PEAssembly::GetMDImport()
{
WRAPPER_NO_CONTRACT;
- if (m_bHasPersistentMDImport)
- return IMDInternalImportHolder(GetPersistentMDImport(),FALSE);
- else
- return IMDInternalImportHolder(GetMDImportWithRef(),TRUE);
-};
-inline IMDInternalImport* PEFile::GetPersistentMDImport()
-{
-/*
- CONTRACT(IMDInternalImport *)
- {
- INSTANCE_CHECK;
- PRECONDITION(!IsResource());
- POSTCONDITION(CheckPointer(RETVAL));
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-*/
- SUPPORTS_DAC;
-#if !defined(__GNUC__)
-
- _ASSERTE(!IsResource());
-#endif
#ifdef DACCESS_COMPILE
WRAPPER_NO_CONTRACT;
return DacGetMDImport(this, true);
@@ -355,56 +276,16 @@ inline IMDInternalImport* PEFile::GetPersistentMDImport()
return m_pMDImport;
#endif
-}
-
-inline IMDInternalImport *PEFile::GetMDImportWithRef()
-{
-/*
- CONTRACT(IMDInternalImport *)
- {
- INSTANCE_CHECK;
- PRECONDITION(!IsResource());
- POSTCONDITION(CheckPointer(RETVAL));
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-*/
-#if !defined(__GNUC__)
- _ASSERTE(!IsResource());
-#endif
-#ifdef DACCESS_COMPILE
- WRAPPER_NO_CONTRACT;
- return DacGetMDImport(this, true);
-#else
- CONTRACTL
- {
- NOTHROW;
- WRAPPER(GC_TRIGGERS);
- MODE_ANY;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- GCX_PREEMP();
- SimpleReadLockHolder lock(m_pMetadataLock);
- if(m_pMDImport)
- m_pMDImport->AddRef();
- return m_pMDImport;
-#endif
-}
+};
#ifndef DACCESS_COMPILE
-inline IMetaDataImport2 *PEFile::GetRWImporter()
+inline IMetaDataImport2 *PEAssembly::GetRWImporter()
{
CONTRACT(IMetaDataImport2 *)
{
INSTANCE_CHECK;
- PRECONDITION(!IsResource());
POSTCONDITION(CheckPointer(RETVAL));
- PRECONDITION(m_bHasPersistentMDImport);
GC_NOTRIGGER;
THROWS;
MODE_ANY;
@@ -417,16 +298,14 @@ inline IMetaDataImport2 *PEFile::GetRWImporter()
RETURN m_pImporter;
}
-inline IMetaDataEmit *PEFile::GetEmitter()
+inline IMetaDataEmit *PEAssembly::GetEmitter()
{
CONTRACT(IMetaDataEmit *)
{
INSTANCE_CHECK;
MODE_ANY;
GC_NOTRIGGER;
- PRECONDITION(!IsResource());
POSTCONDITION(CheckPointer(RETVAL));
- PRECONDITION(m_bHasPersistentMDImport);
THROWS;
}
CONTRACT_END;
@@ -440,40 +319,10 @@ inline IMetaDataEmit *PEFile::GetEmitter()
#endif // DACCESS_COMPILE
-// The simple name is not actually very simple. The name returned comes from one of
-// various metadata tables, depending on whether this is a manifest module,
-// non-manifest module, or something else
-inline LPCUTF8 PEFile::GetSimpleName()
-{
- CONTRACT(LPCUTF8)
- {
- INSTANCE_CHECK;
- MODE_ANY;
- POSTCONDITION(CheckPointer(RETVAL));
- NOTHROW;
- SUPPORTS_DAC;
- WRAPPER(GC_TRIGGERS);
- }
- CONTRACT_END;
-
- if (IsAssembly())
- RETURN dac_cast(this)->GetSimpleName();
- else
- {
- LPCUTF8 szScopeName;
- if (FAILED(GetScopeName(&szScopeName)))
- {
- szScopeName = "";
- }
- RETURN szScopeName;
- }
-}
-
-
// Same as the managed Module.ScopeName property, this unconditionally looks in the
// metadata Module table to get the name. Useful for profilers and others who don't
// like sugar coating on their names.
-inline HRESULT PEFile::GetScopeName(LPCUTF8 * pszName)
+inline HRESULT PEAssembly::GetScopeName(LPCUTF8 * pszName)
{
CONTRACTL
{
@@ -493,14 +342,7 @@ inline HRESULT PEFile::GetScopeName(LPCUTF8 * pszName)
// PE file access
// ------------------------------------------------------------
-inline BOOL PEFile::IsIbcOptimized()
-{
- WRAPPER_NO_CONTRACT;
-
- return FALSE;
-}
-
-inline BOOL PEFile::IsReadyToRun()
+inline BOOL PEAssembly::IsReadyToRun()
{
CONTRACTL
{
@@ -511,9 +353,9 @@ inline BOOL PEFile::IsReadyToRun()
}
CONTRACTL_END;
- if (HasOpenedILimage())
+ if (HasPEImage())
{
- return GetLoadedIL()->HasReadyToRunHeader();
+ return GetLoadedLayout()->HasReadyToRunHeader();
}
else
{
@@ -521,63 +363,37 @@ inline BOOL PEFile::IsReadyToRun()
}
}
-inline WORD PEFile::GetSubsystem()
-{
- WRAPPER_NO_CONTRACT;
-
- if (IsResource() || IsDynamic())
- return 0;
-
- return GetLoadedIL()->GetSubsystem();
-}
-
-inline mdToken PEFile::GetEntryPointToken(
-#ifdef _DEBUG
- BOOL bAssumeLoaded
-#endif //_DEBUG
- )
+inline mdToken PEAssembly::GetEntryPointToken()
{
WRAPPER_NO_CONTRACT;
- if (IsResource() || IsDynamic())
+ if (IsDynamic())
return mdTokenNil;
- _ASSERTE (!bAssumeLoaded || HasLoadedIL ());
- return GetOpenedILimage()->GetEntryPointToken();
+ return GetPEImage()->GetEntryPointToken();
}
-inline BOOL PEFile::IsILOnly()
+inline BOOL PEAssembly::IsILOnly()
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
CONTRACT_VIOLATION(ThrowsViolation|GCViolation|FaultViolation);
- if (IsResource() || IsDynamic())
+ if (IsDynamic())
return FALSE;
- return GetOpenedILimage()->IsILOnly();
-}
-
-inline BOOL PEFile::IsDll()
-{
- WRAPPER_NO_CONTRACT;
-
- if (IsResource() || IsDynamic())
- return TRUE;
-
- return GetOpenedILimage()->IsDll();
+ return GetPEImage()->IsILOnly();
}
-inline PTR_VOID PEFile::GetRvaField(RVA field)
+inline PTR_VOID PEAssembly::GetRvaField(RVA field)
{
CONTRACT(void *)
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
PRECONDITION(CheckRvaField(field));
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -589,17 +405,16 @@ inline PTR_VOID PEFile::GetRvaField(RVA field)
// Note that the native image Rva fields are currently cut off before
// this point. We should not get here for an IL only native image.
- RETURN dac_cast(GetLoadedIL()->GetRvaData(field,NULL_OK));
+ RETURN dac_cast(GetLoadedLayout()->GetRvaData(field,NULL_OK));
}
-inline CHECK PEFile::CheckRvaField(RVA field)
+inline CHECK PEAssembly::CheckRvaField(RVA field)
{
CONTRACT_CHECK
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -609,18 +424,17 @@ inline CHECK PEFile::CheckRvaField(RVA field)
// Note that the native image Rva fields are currently cut off before
// this point. We should not get here for an IL only native image.
- CHECK(GetLoadedIL()->CheckRva(field,NULL_OK));
+ CHECK(GetLoadedLayout()->CheckRva(field,NULL_OK));
CHECK_OK;
}
-inline CHECK PEFile::CheckRvaField(RVA field, COUNT_T size)
+inline CHECK PEAssembly::CheckRvaField(RVA field, COUNT_T size)
{
CONTRACT_CHECK
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -630,11 +444,11 @@ inline CHECK PEFile::CheckRvaField(RVA field, COUNT_T size)
// Note that the native image Rva fields are currently cut off before
// this point. We should not get here for an IL only native image.
- CHECK(GetLoadedIL()->CheckRva(field, size,0,NULL_OK));
+ CHECK(GetLoadedLayout()->CheckRva(field, size,0,NULL_OK));
CHECK_OK;
}
-inline BOOL PEFile::HasTls()
+inline BOOL PEAssembly::HasTls()
{
CONTRACTL
{
@@ -642,24 +456,21 @@ inline BOOL PEFile::HasTls()
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
- PRECONDITION(CheckLoaded());
+ PRECONDITION(IsLoaded());
}
CONTRACTL_END;
- // Resource modules do not contain TLS data.
- if (IsResource())
- return FALSE;
// Dynamic modules do not contain TLS data.
- else if (IsDynamic())
+ if (IsDynamic())
return FALSE;
// ILOnly modules do not contain TLS data.
else if (IsILOnly())
return FALSE;
else
- return GetLoadedIL()->HasTls();
+ return GetLoadedLayout()->HasTls();
}
-inline BOOL PEFile::IsRvaFieldTls(RVA field)
+inline BOOL PEAssembly::IsRvaFieldTls(RVA field)
{
CONTRACTL
{
@@ -667,30 +478,30 @@ inline BOOL PEFile::IsRvaFieldTls(RVA field)
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
- PRECONDITION(CheckLoaded());
+ PRECONDITION(IsLoaded());
}
CONTRACTL_END;
if (!HasTls())
return FALSE;
- PTR_VOID address = PTR_VOID(GetLoadedIL()->GetRvaData(field));
+ PTR_VOID address = PTR_VOID(GetLoadedLayout()->GetRvaData(field));
COUNT_T tlsSize;
- PTR_VOID tlsRange = GetLoadedIL()->GetTlsRange(&tlsSize);
+ PTR_VOID tlsRange = GetLoadedLayout()->GetTlsRange(&tlsSize);
return (address >= tlsRange
&& address < (dac_cast(tlsRange)+tlsSize));
}
-inline UINT32 PEFile::GetFieldTlsOffset(RVA field)
+inline UINT32 PEAssembly::GetFieldTlsOffset(RVA field)
{
CONTRACTL
{
INSTANCE_CHECK;
PRECONDITION(CheckRvaField(field));
PRECONDITION(IsRvaFieldTls(field));
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -698,14 +509,14 @@ inline UINT32 PEFile::GetFieldTlsOffset(RVA field)
CONTRACTL_END;
return (UINT32)(dac_cast(GetRvaField(field)) -
- dac_cast(GetLoadedIL()->GetTlsRange()));
+ dac_cast(GetLoadedLayout()->GetTlsRange()));
}
-inline UINT32 PEFile::GetTlsIndex()
+inline UINT32 PEAssembly::GetTlsIndex()
{
CONTRACTL
{
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
INSTANCE_CHECK;
PRECONDITION(HasTls());
NOTHROW;
@@ -714,18 +525,17 @@ inline UINT32 PEFile::GetTlsIndex()
}
CONTRACTL_END;
- return GetLoadedIL()->GetTlsIndex();
+ return GetLoadedLayout()->GetTlsIndex();
}
-inline const void *PEFile::GetInternalPInvokeTarget(RVA target)
+inline const void *PEAssembly::GetInternalPInvokeTarget(RVA target)
{
CONTRACT(void *)
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
PRECONDITION(CheckInternalPInvokeTarget(target));
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -733,17 +543,16 @@ inline const void *PEFile::GetInternalPInvokeTarget(RVA target)
}
CONTRACT_END;
- RETURN (void*)GetLoadedIL()->GetRvaData(target);
+ RETURN (void*)GetLoadedLayout()->GetRvaData(target);
}
-inline CHECK PEFile::CheckInternalPInvokeTarget(RVA target)
+inline CHECK PEAssembly::CheckInternalPInvokeTarget(RVA target)
{
CONTRACT_CHECK
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -751,16 +560,16 @@ inline CHECK PEFile::CheckInternalPInvokeTarget(RVA target)
CONTRACT_CHECK_END;
CHECK(!IsILOnly());
- CHECK(GetLoadedIL()->CheckRva(target));
+ CHECK(GetLoadedLayout()->CheckRva(target));
CHECK_OK;
}
-inline IMAGE_COR_VTABLEFIXUP *PEFile::GetVTableFixups(COUNT_T *pCount/*=NULL*/)
+inline IMAGE_COR_VTABLEFIXUP *PEAssembly::GetVTableFixups(COUNT_T *pCount/*=NULL*/)
{
CONTRACT(IMAGE_COR_VTABLEFIXUP *)
{
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
INSTANCE_CHECK;
NOTHROW;
GC_NOTRIGGER;
@@ -769,26 +578,25 @@ inline IMAGE_COR_VTABLEFIXUP *PEFile::GetVTableFixups(COUNT_T *pCount/*=NULL*/)
}
CONTRACT_END;
- if (IsResource() || IsDynamic() || IsILOnly())
+ if (IsDynamic() || IsILOnly())
{
if (pCount != NULL)
*pCount = 0;
RETURN NULL;
}
else
- RETURN GetLoadedIL()->GetVTableFixups(pCount);
+ RETURN GetLoadedLayout()->GetVTableFixups(pCount);
}
-inline void *PEFile::GetVTable(RVA rva)
+inline void *PEAssembly::GetVTable(RVA rva)
{
CONTRACT(void *)
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
PRECONDITION(!IsILOnly());
- PRECONDITION(GetLoadedIL()->CheckRva(rva));
+ PRECONDITION(GetLoadedLayout()->CheckRva(rva));
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
@@ -796,18 +604,17 @@ inline void *PEFile::GetVTable(RVA rva)
}
CONTRACT_END;
- RETURN (void *)GetLoadedIL()->GetRvaData(rva);
+ RETURN (void *)GetLoadedLayout()->GetRvaData(rva);
}
// @todo: this is bad to expose. But it is needed to support current IJW thunks
-inline HMODULE PEFile::GetIJWBase()
+inline HMODULE PEAssembly::GetIJWBase()
{
CONTRACTL
{
INSTANCE_CHECK;
PRECONDITION(!IsDynamic());
- PRECONDITION(!IsResource());
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
PRECONDITION(!IsILOnly());
NOTHROW;
GC_NOTRIGGER;
@@ -815,10 +622,10 @@ inline HMODULE PEFile::GetIJWBase()
}
CONTRACTL_END;
- return (HMODULE) dac_cast(GetLoadedIL()->GetBase());
+ return (HMODULE) dac_cast(GetLoadedLayout()->GetBase());
}
-inline PTR_VOID PEFile::GetDebuggerContents(COUNT_T *pSize/*=NULL*/)
+inline PTR_VOID PEAssembly::GetDebuggerContents(COUNT_T *pSize/*=NULL*/)
{
CONTRACT(PTR_VOID)
{
@@ -835,12 +642,12 @@ inline PTR_VOID PEFile::GetDebuggerContents(COUNT_T *pSize/*=NULL*/)
// helper thread. The debugger will have to expect a zero base
// in some circumstances.
- if (IsLoaded())
+ if (HasLoadedPEImage())
{
if (pSize != NULL)
- *pSize = GetLoaded()->GetSize();
+ *pSize = GetLoadedLayout()->GetSize();
- RETURN GetLoaded()->GetBase();
+ RETURN GetLoadedLayout()->GetBase();
}
else
{
@@ -851,7 +658,7 @@ inline PTR_VOID PEFile::GetDebuggerContents(COUNT_T *pSize/*=NULL*/)
}
}
-inline PTR_CVOID PEFile::GetLoadedImageContents(COUNT_T *pSize/*=NULL*/)
+inline PTR_CVOID PEAssembly::GetLoadedImageContents(COUNT_T *pSize/*=NULL*/)
{
CONTRACTL
{
@@ -863,13 +670,13 @@ inline PTR_CVOID PEFile::GetLoadedImageContents(COUNT_T *pSize/*=NULL*/)
}
CONTRACTL_END;
- if (IsLoaded() && !IsDynamic())
+ if (HasLoadedPEImage())
{
if (pSize != NULL)
{
- *pSize = GetLoaded()->GetSize();
+ *pSize = GetLoadedLayout()->GetSize();
}
- return GetLoaded()->GetBase();
+ return GetLoadedLayout()->GetBase();
}
else
{
@@ -882,32 +689,32 @@ inline PTR_CVOID PEFile::GetLoadedImageContents(COUNT_T *pSize/*=NULL*/)
}
#ifndef DACCESS_COMPILE
-inline const void *PEFile::GetManagedFileContents(COUNT_T *pSize/*=NULL*/)
+inline const void *PEAssembly::GetManagedFileContents(COUNT_T *pSize/*=NULL*/)
{
CONTRACT(const void *)
{
INSTANCE_CHECK;
- PRECONDITION(CheckLoaded());
+ PRECONDITION(HasLoadedPEImage());
WRAPPER(THROWS);
WRAPPER(GC_TRIGGERS);
MODE_ANY;
- POSTCONDITION((!GetLoaded()->GetSize()) || CheckPointer(RETVAL));
+ POSTCONDITION((!GetLoadedLayout()->GetSize()) || CheckPointer(RETVAL));
}
CONTRACT_END;
// Right now, we will trigger a LoadLibrary for the caller's sake,
// even if we are in a scenario where we could normally avoid it.
- LoadLibrary(FALSE);
+ EnsureLoaded();
if (pSize != NULL)
- *pSize = GetLoadedIL()->GetSize();
+ *pSize = GetLoadedLayout()->GetSize();
- RETURN GetLoadedIL()->GetBase();
+ RETURN GetLoadedLayout()->GetBase();
}
#endif // DACCESS_COMPILE
-inline BOOL PEFile::IsPtrInILImage(PTR_CVOID data)
+inline BOOL PEAssembly::IsPtrInPEImage(PTR_CVOID data)
{
CONTRACTL
{
@@ -919,49 +726,13 @@ inline BOOL PEFile::IsPtrInILImage(PTR_CVOID data)
}
CONTRACTL_END;
- if (HasOpenedILimage())
+ if (HasPEImage())
{
- return GetOpenedILimage()->IsPtrInImage(data);
+ return GetPEImage()->IsPtrInImage(data);
}
else
return FALSE;
}
-// ------------------------------------------------------------
-// Native image access
-// ------------------------------------------------------------
-
-inline PTR_PEImageLayout PEFile::GetLoadedIL()
-{
- LIMITED_METHOD_CONTRACT;
- SUPPORTS_DAC;
-
- _ASSERTE(HasOpenedILimage());
-
- return GetOpenedILimage()->GetLoadedLayout();
-};
-
-inline BOOL PEFile::IsLoaded(BOOL bAllowNative/*=TRUE*/)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- if(IsDynamic())
- return TRUE;
- return HasLoadedIL();
-};
-
-
-inline PTR_PEImageLayout PEFile::GetLoaded()
-{
- WRAPPER_NO_CONTRACT;
- SUPPORTS_DAC;
- return GetLoadedIL();
-};
-
// ------------------------------------------------------------
// Descriptive strings
@@ -995,14 +766,14 @@ inline LPCSTR PEAssembly::GetSimpleName()
CONTRACTL
{
NOTHROW;
- if (!m_bHasPersistentMDImport) { GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);};
+ DISABLED(GC_TRIGGERS);
MODE_ANY;
SUPPORTS_DAC;
}
CONTRACTL_END;
LPCSTR name = "";
- IMDInternalImportHolder pImport = GetMDImport();
+ IMDInternalImport* pImport = GetMDImport();
if (pImport != NULL)
{
if (FAILED(pImport->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, &name, NULL, NULL)))
@@ -1014,7 +785,7 @@ inline LPCSTR PEAssembly::GetSimpleName()
return name;
}
-inline BOOL PEFile::IsStrongNamed()
+inline BOOL PEAssembly::IsStrongNamed()
{
CONTRACTL
{
@@ -1035,7 +806,7 @@ inline BOOL PEFile::IsStrongNamed()
// Check to see if this assembly has had its strong name signature verified yet.
//
-inline const void *PEFile::GetPublicKey(DWORD *pcbPK)
+inline const void *PEAssembly::GetPublicKey(DWORD *pcbPK)
{
CONTRACTL
{
@@ -1051,7 +822,7 @@ inline const void *PEFile::GetPublicKey(DWORD *pcbPK)
return pPK;
}
-inline ULONG PEFile::GetHashAlgId()
+inline ULONG PEAssembly::GetHashAlgId()
{
CONTRACTL
{
@@ -1066,7 +837,7 @@ inline ULONG PEFile::GetHashAlgId()
return hashAlgId;
}
-inline LPCSTR PEFile::GetLocale()
+inline LPCSTR PEAssembly::GetLocale()
{
CONTRACTL
{
@@ -1081,11 +852,10 @@ inline LPCSTR PEFile::GetLocale()
return md.szLocale;
}
-inline DWORD PEFile::GetFlags()
+inline DWORD PEAssembly::GetFlags()
{
CONTRACTL
{
- PRECONDITION(IsAssembly());
INSTANCE_CHECK;
if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
@@ -1099,43 +869,4 @@ inline DWORD PEFile::GetFlags()
return flags;
}
-// In the cases where you know the module is loaded, and cannot tolerate triggering and
-// loading, this alternative to PEFile::GetFlags is useful. Profiling API uses this.
-inline HRESULT PEFile::GetFlagsNoTrigger(DWORD * pdwFlags)
-{
- CONTRACTL
- {
- PRECONDITION(IsAssembly());
- INSTANCE_CHECK;
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- _ASSERTE (pdwFlags != NULL);
-
- if (!m_bHasPersistentMDImport)
- return E_FAIL;
-
- return GetPersistentMDImport()->GetAssemblyProps(TokenFromRid(1, mdtAssembly), NULL, NULL, NULL, NULL, NULL, pdwFlags);
-}
-
-// ------------------------------------------------------------
-// Metadata access
-// ------------------------------------------------------------
-
-inline void PEFile::OpenMDImport()
-{
- WRAPPER_NO_CONTRACT;
- //need synchronization
- _ASSERTE(m_pMetadataLock->LockTaken() && m_pMetadataLock->IsWriterLock());
- OpenMDImport_Unsafe();
-}
-
-inline PEFile* PEFile::Dummy()
-{
- return (PEFile*)(-1);
-}
-#endif // PEFILE_INL_
+#endif // PEASSEMBLY_INL_
diff --git a/src/coreclr/vm/peimage.cpp b/src/coreclr/vm/peimage.cpp
index 412d67c938f5e..25aeb9625ec66 100644
--- a/src/coreclr/vm/peimage.cpp
+++ b/src/coreclr/vm/peimage.cpp
@@ -61,44 +61,20 @@ CHECK PEImage::CheckStartup()
CHECK_OK;
}
-/* static */
-CHECK PEImage::CheckLayoutFormat(PEDecoder *pe)
-{
- CONTRACT_CHECK
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACT_CHECK_END;
-
- CHECK(pe->IsILOnly());
- CHECK_OK;
-}
-
CHECK PEImage::CheckILFormat()
{
WRAPPER_NO_CONTRACT;
-
- PTR_PEImageLayout pLayoutToCheck;
- PEImageLayoutHolder pLayoutHolder;
-
- if (HasLoadedLayout())
- {
- pLayoutToCheck = GetLoadedLayout();
- }
- else
- {
- pLayoutHolder = GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED);
- pLayoutToCheck = pLayoutHolder;
- }
-
- CHECK(pLayoutToCheck->CheckILFormat());
-
+ CHECK(GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->CheckILFormat());
CHECK_OK;
};
+// PEImage is always unique on CoreCLR so a simple pointer check is sufficient in PEImage::Equals
+CHECK PEImage::CheckUniqueInstance()
+{
+ CHECK(GetPath().IsEmpty() || m_bInHashMap);
+ CHECK_OK;
+}
+
PEImage::~PEImage()
{
CONTRACTL
@@ -116,7 +92,7 @@ PEImage::~PEImage()
if (m_pLayoutLock)
delete m_pLayoutLock;
- if(m_hFile!=INVALID_HANDLE_VALUE && m_bOwnHandle)
+ if(m_hFile!=INVALID_HANDLE_VALUE)
CloseHandle(m_hFile);
for (unsigned int i=0;iDeleteValue(GetIDHash(), &locator);
+ PEImage* deleted = (PEImage *)s_Images->DeleteValue(GetPathHash(), &locator);
_ASSERTE(deleted == this);
}
}
@@ -252,44 +228,6 @@ CHECK PEImage::CheckCanonicalFullPath(const SString &path)
CHECK_OK;
}
-BOOL PEImage::PathEquals(const SString &p1, const SString &p2)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
- return p1.Equals(p2);
-#else
- return p1.EqualsCaseInsensitive(p2);
-#endif
-}
-
-#ifndef TARGET_UNIX
-/* static */
-void PEImage::GetPathFromDll(HINSTANCE hMod, SString &result)
-{
- CONTRACTL
- {
- PRECONDITION(CheckStartup());
- PRECONDITION(CheckPointer(hMod));
- PRECONDITION(CheckValue(result));
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM(););
- }
- CONTRACTL_END;
-
- WszGetModuleFileName(hMod, result);
-
-}
-#endif // !TARGET_UNIX
-
/* static */
BOOL PEImage::CompareImage(UPTR u1, UPTR u2)
{
@@ -307,16 +245,25 @@ BOOL PEImage::CompareImage(UPTR u1, UPTR u2)
// This is the value stored in the table
PEImage *pImage = (PEImage *) u2;
+ if (pLocator->m_bIsInBundle != pImage->IsInBundle())
+ {
+ return FALSE;
+ }
BOOL ret = FALSE;
HRESULT hr;
EX_TRY
{
SString path(SString::Literal, pLocator->m_pPath);
- BOOL isInBundle = pLocator->m_bIsInBundle;
- if (PathEquals(path, pImage->GetPath()) &&
- (!isInBundle == !pImage->IsInBundle()))
+
+#ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
+ if (pImage->GetPath().Equals(path))
+#else
+ if (pImage->GetPath().EqualsCaseInsensitive(path))
+#endif
+ {
ret = TRUE;
+ }
}
EX_CATCH_HRESULT(hr); //ignores failure!
return ret;
@@ -335,8 +282,8 @@ BOOL PEImage::Equals(PEImage *pImage)
CONTRACTL_END;
// PEImage is always unique on CoreCLR so a simple pointer check is sufficient
- _ASSERTE(m_bInHashMap || GetPath().IsEmpty());
- _ASSERTE(pImage->m_bInHashMap || pImage->GetPath().IsEmpty());
+ _ASSERTE(CheckUniqueInstance());
+ _ASSERTE(pImage->CheckUniqueInstance());
return dac_cast(pImage) == dac_cast(this);
}
@@ -791,18 +738,16 @@ void PEImage::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
PEImage::PEImage():
m_path(),
m_refCount(1),
- m_bundleFileLocation(),
m_bInHashMap(FALSE),
+ m_bundleFileLocation(),
+ m_hFile(INVALID_HANDLE_VALUE),
+ m_dwPEKind(0),
+ m_dwMachine(0),
#ifdef METADATATRACKER_DATA
m_pMDTracker(NULL),
#endif // METADATATRACKER_DATA
m_pMDImport(NULL),
- m_pNativeMDImport(NULL),
- m_hFile(INVALID_HANDLE_VALUE),
- m_bOwnHandle(true),
- m_dwPEKind(0),
- m_dwMachine(0),
- m_fCachedKindAndMachine(FALSE)
+ m_pNativeMDImport(NULL)
{
CONTRACTL
{
@@ -816,48 +761,48 @@ PEImage::PEImage():
m_pLayoutLock=new SimpleRWLock(PREEMPTIVE,LOCK_TYPE_DEFAULT);
}
-PTR_PEImageLayout PEImage::GetLayout(DWORD imageLayoutMask,DWORD flags)
+// Misnomer under the DAC, but has a lot of callers. The DAC can't create layouts, so in that
+// case this is a get.
+PTR_PEImageLayout PEImage::GetOrCreateLayout(DWORD imageLayoutMask)
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- PTR_PEImageLayout pRetVal;
-
-#ifndef DACCESS_COMPILE
- // First attempt to find an existing layout matching imageLayoutMask. If that fails,
- // and the caller has asked us to create layouts if needed, then try again passing
- // the create flag to GetLayoutInternal. We need this to be synchronized, but the common
- // case is that the layout already exists, so use a reader-writer lock.
- GCX_PREEMP();
- {
- SimpleReadLockHolder lock(m_pLayoutLock);
- pRetVal=GetLayoutInternal(imageLayoutMask,flags&(~LAYOUT_CREATEIFNEEDED));
- }
+ // First attempt to find an existing layout matching imageLayoutMask.
+ // If that fails, try again with auto-creating helper.
+ // Note: we use reader-writer lock, but only writes are synchronized.
+ PTR_PEImageLayout pRetVal = GetExistingLayoutInternal(imageLayoutMask);
- if (!(pRetVal || (flags&LAYOUT_CREATEIFNEEDED)==0))
+ if (pRetVal == NULL)
{
+#ifndef DACCESS_COMPILE
+ GCX_PREEMP();
SimpleWriteLockHolder lock(m_pLayoutLock);
- pRetVal = GetLayoutInternal(imageLayoutMask,flags);
- }
-
- return pRetVal;
-
+ pRetVal = GetOrCreateLayoutInternal(imageLayoutMask);
#else
- // In DAC builds, we can't create any layouts - we must require that they already exist.
- // We also don't take any AddRefs or locks in DAC builds - it's inspection-only.
- pRetVal = GetExistingLayoutInternal(imageLayoutMask);
- if ((pRetVal==NULL) && (flags & LAYOUT_CREATEIFNEEDED))
- {
+ // In DAC builds, we can't create any layouts - we must require that they already exist.
+ // We also don't take any AddRefs or locks in DAC builds - it's inspection-only.
_ASSERTE_MSG(false, "DACization error - caller expects PEImage layout to exist and it doesn't");
DacError(E_UNEXPECTED);
+#endif
}
+
return pRetVal;
-#endif
}
#ifndef DACCESS_COMPILE
-PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags)
+void PEImage::SetLayout(DWORD dwLayout, PEImageLayout* pLayout)
+{
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwLayout < IMAGE_COUNT);
+ _ASSERTE(m_pLayoutLock->IsWriterLock());
+ _ASSERTE(m_pLayouts[dwLayout] == NULL);
+
+ m_pLayouts[dwLayout] = pLayout;
+}
+
+PTR_PEImageLayout PEImage::GetOrCreateLayoutInternal(DWORD imageLayoutMask)
{
CONTRACTL
{
@@ -869,9 +814,9 @@ PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags)
PTR_PEImageLayout pRetVal=GetExistingLayoutInternal(imageLayoutMask);
- if (pRetVal==NULL && (flags&LAYOUT_CREATEIFNEEDED))
+ if (pRetVal==NULL)
{
- _ASSERTE(HasID());
+ _ASSERTE(HasPath());
BOOL bIsMappedLayoutSuitable = ((imageLayoutMask & PEImageLayout::LAYOUT_MAPPED) != 0);
BOOL bIsFlatLayoutSuitable = ((imageLayoutMask & PEImageLayout::LAYOUT_FLAT) != 0);
@@ -906,11 +851,8 @@ PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags)
}
}
- if (pRetVal != NULL)
- {
- pRetVal->AddRef();
- }
-
+ _ASSERTE(pRetVal != NULL);
+ _ASSERTE(this->IsOpened());
return pRetVal;
}
@@ -982,9 +924,10 @@ PTR_PEImageLayout PEImage::CreateLayoutMapped()
}
else
{
- PEImageLayoutHolder flatPE(GetLayoutInternal(PEImageLayout::LAYOUT_FLAT,LAYOUT_CREATEIFNEEDED));
+ PEImageLayout* flatPE = GetOrCreateLayout(PEImageLayout::LAYOUT_FLAT);
if (!flatPE->CheckFormat() || !flatPE->IsILOnly())
ThrowHR(COR_E_BADIMAGEFORMAT);
+
pRetVal=PEImageLayout::LoadFromFlat(flatPE);
SetLayout(IMAGE_MAPPED,pRetVal);
}
@@ -1034,6 +977,9 @@ PTR_PEImage PEImage::LoadFlat(const void *flat, COUNT_T size)
PEImageHolder pImage(new PEImage());
PTR_PEImageLayout pLayout = PEImageLayout::CreateFlat(flat,size,pImage);
_ASSERTE(!pLayout->IsMapped());
+
+ SimpleWriteLockHolder lock(pImage->m_pLayoutLock);
+
pImage->SetLayout(IMAGE_FLAT,pLayout);
RETURN dac_cast(pImage.Extract());
}
@@ -1051,8 +997,8 @@ PTR_PEImage PEImage::LoadImage(HMODULE hMod)
CONTRACT_END;
StackSString path;
- GetPathFromDll(hMod, path);
- PEImageHolder pImage(PEImage::OpenImage(path,(MDInternalImportFlags)(0)));
+ WszGetModuleFileName(hMod, path);
+ PEImageHolder pImage(PEImage::OpenImage(path, MDInternalImport_Default));
if (pImage->HasLoadedLayout())
RETURN dac_cast(pImage.Extract());
@@ -1134,18 +1080,6 @@ void PEImage::Load()
}
}
-void PEImage::SetLoadedHMODULE(HMODULE hMod)
-{
- WRAPPER_NO_CONTRACT;
- SimpleWriteLockHolder lock(m_pLayoutLock);
- if(m_pLayouts[IMAGE_LOADED])
- {
- _ASSERTE(m_pLayouts[IMAGE_LOADED]->GetBase()==hMod);
- return;
- }
- SetLayout(IMAGE_LOADED,PEImageLayout::CreateFromHMODULE(hMod,this,TRUE));
-}
-
void PEImage::LoadFromMapped()
{
STANDARD_VM_CONTRACT;
@@ -1156,10 +1090,13 @@ void PEImage::LoadFromMapped()
return;
}
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_MAPPED,LAYOUT_CREATEIFNEEDED));
+ PEImageLayout* pLayout = GetOrCreateLayout(PEImageLayout::LAYOUT_MAPPED);
SimpleWriteLockHolder lock(m_pLayoutLock);
- if(m_pLayouts[IMAGE_LOADED]==NULL)
- SetLayout(IMAGE_LOADED,pLayout.Extract());
+ if (m_pLayouts[IMAGE_LOADED] == NULL)
+ {
+ pLayout->AddRef();
+ SetLayout(IMAGE_LOADED, pLayout);
+ }
}
void PEImage::LoadNoFile()
@@ -1173,38 +1110,18 @@ void PEImage::LoadNoFile()
if (HasLoadedLayout())
return;
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,0));
+ PEImageLayout* pLayout = GetExistingLayoutInternal(PEImageLayout::LAYOUT_ANY);
if (!pLayout->CheckILOnly())
ThrowHR(COR_E_BADIMAGEFORMAT);
- SimpleWriteLockHolder lock(m_pLayoutLock);
- if(m_pLayouts[IMAGE_LOADED]==NULL)
- SetLayout(IMAGE_LOADED,pLayout.Extract());
-}
-
-
-void PEImage::LoadNoMetaData()
-{
- STANDARD_VM_CONTRACT;
-
- if (HasLoadedLayout())
- return;
SimpleWriteLockHolder lock(m_pLayoutLock);
- if (m_pLayouts[IMAGE_LOADED]!=NULL)
- return;
- if (m_pLayouts[IMAGE_FLAT]!=NULL)
+ if (m_pLayouts[IMAGE_LOADED] == NULL)
{
- m_pLayouts[IMAGE_FLAT]->AddRef();
- SetLayout(IMAGE_LOADED,m_pLayouts[IMAGE_FLAT]);
- }
- else
- {
- _ASSERTE(!m_path.IsEmpty());
- SetLayout(IMAGE_LOADED,PEImageLayout::LoadFlat(this));
+ pLayout->AddRef();
+ SetLayout(IMAGE_LOADED, pLayout);
}
}
-
#endif //DACCESS_COMPILE
//-------------------------------------------------------------------------------
@@ -1264,22 +1181,6 @@ HANDLE PEImage::GetFileHandle()
return m_hFile;
}
-void PEImage::SetFileHandle(HANDLE hFile)
-{
- CONTRACTL
- {
- STANDARD_VM_CHECK;
- }
- CONTRACTL_END;
-
- SimpleWriteLockHolder lock(m_pLayoutLock);
- if (m_hFile == INVALID_HANDLE_VALUE)
- {
- m_hFile = hFile;
- m_bOwnHandle = false;
- }
-}
-
HRESULT PEImage::TryOpenFile()
{
STANDARD_VM_CONTRACT;
@@ -1290,7 +1191,7 @@ HRESULT PEImage::TryOpenFile()
return S_OK;
{
ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
- m_hFile=WszCreateFile((LPCWSTR)GetPathToLoad(),
+ m_hFile=WszCreateFile((LPCWSTR)GetPathToLoad(),
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL,
diff --git a/src/coreclr/vm/peimage.h b/src/coreclr/vm/peimage.h
index af86e35ccaec4..679b3e024d337 100644
--- a/src/coreclr/vm/peimage.h
+++ b/src/coreclr/vm/peimage.h
@@ -26,9 +26,6 @@ class SimpleRWLock;
// --------------------------------------------------------------------------------
class Crst;
-class Thread;
-
-Thread* GetThreadNULLOk();
// --------------------------------------------------------------------------------
// PEImage is a PE file loaded by our "simulated LoadLibrary" mechanism. A PEImage
@@ -56,92 +53,54 @@ struct CV_INFO_PDB70
typedef DPTR(class PEImage) PTR_PEImage;
-class PEImage
+class PEImage final
{
-public:
- // ------------------------------------------------------------
- // Public constants
- // ------------------------------------------------------------
-
- enum
- {
- LAYOUT_CREATEIFNEEDED=1
- };
- PTR_PEImageLayout GetLayout(DWORD imageLayoutMask,DWORD flags); //with ref
- PTR_PEImageLayout GetLoadedLayout(); //no ref
- BOOL IsOpened();
- BOOL HasLoadedLayout();
public:
// ------------------------------------------------------------
// Public API
// ------------------------------------------------------------
+ // initialize static data (i.e. locks, unique instance cache, etc..)
static void Startup();
- // Normal constructed PEImages do NOT share images between calls and
- // cannot be accessed by Get methods.
- //
- // DO NOT USE these unless you want a private copy-on-write mapping of
- // the file.
-
-
-
-public:
~PEImage();
PEImage();
+ BOOL Equals(PEImage* pImage);
+
+ ULONG AddRef();
+ ULONG Release();
+
#ifndef DACCESS_COMPILE
- static PTR_PEImage LoadFlat(
- const void *flat,
- COUNT_T size);
+ static PTR_PEImage LoadFlat(const void *flat, COUNT_T size);
#ifndef TARGET_UNIX
- static PTR_PEImage LoadImage(
- HMODULE hMod);
+ static PTR_PEImage LoadImage(HMODULE hMod);
#endif // !TARGET_UNIX
static PTR_PEImage OpenImage(
LPCWSTR pPath,
MDInternalImportFlags flags = MDInternalImport_Default,
BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid());
-
- // clones the image with new flags (this is pretty much about cached / noncached difference)
- void Clone(MDInternalImportFlags flags, PTR_PEImage* ppImage)
- {
- if (GetPath().IsEmpty())
- {
- AddRef();
- *ppImage = this;
- }
- else
- *ppImage = PEImage::OpenImage(GetPath(), flags);
-
- };
-
- static PTR_PEImage FindById(UINT64 uStreamAsmId, DWORD dwModuleId);
- static PTR_PEImage FindByPath(LPCWSTR pPath,
- BOOL isInBundle = TRUE);
- static PTR_PEImage FindByShortPath(LPCWSTR pPath);
- static PTR_PEImage FindByLongPath(LPCWSTR pPath);
+ static PTR_PEImage FindByPath(LPCWSTR pPath, BOOL isInBundle = TRUE);
void AddToHashMap();
void Load();
- void SetLoadedHMODULE(HMODULE hMod);
- void LoadNoMetaData();
void LoadNoFile();
void LoadFromMapped();
#endif
- BOOL HasID();
- ULONG GetIDHash();
+ BOOL IsOpened();
+ PTR_PEImageLayout GetOrCreateLayout(DWORD imageLayoutMask);
- // Refcount above images.
- ULONG AddRef();
- ULONG Release();
+ BOOL HasLoadedLayout();
+ PTR_PEImageLayout GetLoadedLayout();
- // Accessors
- const SString &GetPath();
+ BOOL HasPath();
+ ULONG GetPathHash();
+ const SString& GetPath();
const SString& GetPathToLoad();
+
BOOL IsFile();
BOOL IsInBundle() const;
HANDLE GetFileHandle();
@@ -149,14 +108,10 @@ class PEImage
INT64 GetSize() const;
INT64 GetUncompressedSize() const;
- void SetFileHandle(HANDLE hFile);
HRESULT TryOpenFile();
LPCWSTR GetPathForErrorMessages();
- // Equality
- BOOL Equals(PEImage *pImage);
-
void GetMVID(GUID *pMvid);
BOOL HasV1Metadata();
IMDInternalImport* GetMDImport();
@@ -165,54 +120,53 @@ class PEImage
BOOL HasContents() ;
BOOL IsPtrInImage(PTR_CVOID data);
- CHECK CheckFormat();
-
- // Check utilites
- CHECK CheckILFormat();
- static CHECK CheckCanonicalFullPath(const SString &path);
- static CHECK CheckStartup();
- PTR_CVOID GetMetadata(COUNT_T *pSize = NULL);
-
-#ifndef TARGET_UNIX
- static void GetPathFromDll(HINSTANCE hMod, SString &result);
-#endif // !TARGET_UNIX
- static BOOL PathEquals(const SString &p1, const SString &p2);
-
- void SetModuleFileNameHintForDAC();
-#ifdef DACCESS_COMPILE
- void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
- const SString &GetModuleFileNameHintForDAC();
-#endif
BOOL HasNTHeaders();
BOOL HasCorHeader();
BOOL HasReadyToRunHeader();
+ BOOL HasDirectoryEntry(int entry);
+ BOOL Has32BitNTHeaders();
+
+ void GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine);
+
+ BOOL IsILOnly();
BOOL IsReferenceAssembly();
BOOL IsComponentAssembly();
- PTR_CVOID GetNativeManifestMetadata(COUNT_T *pSize = NULL);
- BOOL HasDirectoryEntry(int entry);
+
+ PTR_CVOID GetNativeManifestMetadata(COUNT_T* pSize = NULL);
mdToken GetEntryPointToken();
DWORD GetCorHeaderFlags();
- BOOL IsILOnly();
- BOOL IsDll();
- WORD GetSubsystem();
- BOOL IsFileLocked();
- BOOL IsIbcOptimized();
- BOOL Has32BitNTHeaders();
+ PTR_CVOID GetMetadata(COUNT_T* pSize = NULL);
+
+ // Check utilites
+ static CHECK CheckStartup();
+ static CHECK CheckCanonicalFullPath(const SString& path);
+
+ CHECK CheckFormat();
+ CHECK CheckILFormat();
+ CHECK CheckUniqueInstance();
void VerifyIsAssembly();
+ void SetModuleFileNameHintForDAC();
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+ const SString &GetModuleFileNameHintForDAC();
+#endif
+
private:
#ifndef DACCESS_COMPILE
// Get or create the layout corresponding to the mask, with an AddRef
- PTR_PEImageLayout GetLayoutInternal(DWORD imageLayoutMask, DWORD flags);
+ PTR_PEImageLayout GetOrCreateLayoutInternal(DWORD imageLayoutMask);
// Create the mapped layout
PTR_PEImageLayout CreateLayoutMapped();
// Create the flat layout
PTR_PEImageLayout CreateLayoutFlat(BOOL bPermitWriteableSections);
+
+ void SetLayout(DWORD dwLayout, PTR_PEImageLayout pLayout);
#endif
// Get an existing layout corresponding to the mask, no AddRef
PTR_PEImageLayout GetExistingLayoutInternal(DWORD imageLayoutMask);
@@ -249,28 +203,83 @@ class PEImage
void DECLSPEC_NORETURN ThrowFormat(HRESULT hr);
- static CHECK CheckLayoutFormat(PEDecoder *pe);
+public:
+ class IJWFixupData
+ {
+ private:
+ Crst m_lock;
+ void* m_base;
+ DWORD m_flags;
+ PTR_LoaderHeap m_DllThunkHeap;
+
+ // the fixup for the next iteration in FixupVTables
+ // we use it to make sure that we do not try to fix up the same entry twice
+ // if there was a pass that was aborted in the middle
+ COUNT_T m_iNextFixup;
+ COUNT_T m_iNextMethod;
+
+ enum {
+ e_FIXED_UP = 0x1
+ };
+
+ public:
+ IJWFixupData(void* pBase);
+ ~IJWFixupData();
+ void* GetBase() { LIMITED_METHOD_CONTRACT; return m_base; }
+ Crst* GetLock() { LIMITED_METHOD_CONTRACT; return &m_lock; }
+ BOOL IsFixedUp() { LIMITED_METHOD_CONTRACT; return m_flags & e_FIXED_UP; }
+ void SetIsFixedUp() { LIMITED_METHOD_CONTRACT; m_flags |= e_FIXED_UP; }
+ PTR_LoaderHeap GetThunkHeap();
+ void MarkMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
+ BOOL IsMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
+ };
+
+ static IJWFixupData* GetIJWData(void* pBase);
+ static PTR_LoaderHeap GetDllThunkHeap(void* pBase);
+ static void UnloadIJWModule(void* pBase);
+
+private:
// ------------------------------------------------------------
- // Instance members
+ // Static fields
// ------------------------------------------------------------
- SString m_path;
- LONG m_refCount;
+ static CrstStatic s_hashLock;
+ static PtrHashMap* s_Images;
- BundleFileLocation m_bundleFileLocation; // If this image is located within a single-file bundle,
- // the location within the bundle. If m_bundleFileLocation is valid,
- // it takes precedence over m_path for loading.
+//@TODO:workaround: Remove this when we have one PEImage per mapped image,
+//@TODO:workaround: and move the lock there
+// This is for IJW thunk initialization, as it is no longer guaranteed
+// that the initialization will occur under the loader lock.
+ static CrstStatic s_ijwHashLock;
+ static PtrHashMap* s_ijwFixupDataHash;
+
+ // ------------------------------------------------------------
+ // Instance fields
+ // ------------------------------------------------------------
+
+ SString m_path;
+ LONG m_refCount;
+
+ // means this is a unique (deduped) instance.
+ BOOL m_bInHashMap;
+
+ // If this image is located within a single-file bundle, the location within the bundle.
+ // If m_bundleFileLocation is valid, it takes precedence over m_path for loading.
+ BundleFileLocation m_bundleFileLocation;
+
+ // valid handle if we tried to open the file/path and succeeded.
+ HANDLE m_hFile;
+
+ DWORD m_dwPEKind;
+ DWORD m_dwMachine;
// This variable will have the data of module name.
// It is only used by DAC to remap fusion loaded modules back to
// disk IL. This really is a workaround. The real fix is for fusion loader
// hook (public API on hosting) to take an additional file name hint.
// We are piggy backing on the fact that module name is the same as file name!!!
- //
- SString m_sModuleFileNameHintUsedByDac; // This is only used by DAC
-
-protected:
+ SString m_sModuleFileNameHintUsedByDac; // This is only used by DAC
enum
{
@@ -282,11 +291,6 @@ class PEImage
SimpleRWLock *m_pLayoutLock;
PTR_PEImageLayout m_pLayouts[IMAGE_COUNT] ;
- BOOL m_bInHashMap;
-#ifndef DACCESS_COMPILE
- void SetLayout(DWORD dwLayout, PTR_PEImageLayout pLayout);
-#endif // DACCESS_COMPILE
-
#ifdef METADATATRACKER_DATA
class MetaDataTracker *m_pMDTracker;
@@ -294,75 +298,6 @@ class PEImage
IMDInternalImport* m_pMDImport;
IMDInternalImport* m_pNativeMDImport;
-
-
-private:
-
-
- // ------------------------------------------------------------
- // Static members
- // ------------------------------------------------------------
-
- static CrstStatic s_hashLock;
-
- static PtrHashMap *s_Images;
-
- HANDLE m_hFile;
- bool m_bOwnHandle;
-
- //@TODO:workaround: Remove this when we have one PEImage per mapped image,
- //@TODO:workaround: and move the lock there
- // This is for IJW thunk initialization, as it is no longer guaranteed
- // that the initialization will occur under the loader lock.
- static CrstStatic s_ijwHashLock;
- static PtrHashMap *s_ijwFixupDataHash;
-
-public:
- class IJWFixupData
- {
- private:
- Crst m_lock;
- void *m_base;
- DWORD m_flags;
- PTR_LoaderHeap m_DllThunkHeap;
-
- // the fixup for the next iteration in FixupVTables
- // we use it to make sure that we do not try to fix up the same entry twice
- // if there was a pass that was aborted in the middle
- COUNT_T m_iNextFixup;
- COUNT_T m_iNextMethod;
-
- enum {
- e_FIXED_UP = 0x1
- };
-
- public:
- IJWFixupData(void *pBase);
- ~IJWFixupData();
- void *GetBase() { LIMITED_METHOD_CONTRACT; return m_base; }
- Crst *GetLock() { LIMITED_METHOD_CONTRACT; return &m_lock; }
- BOOL IsFixedUp() { LIMITED_METHOD_CONTRACT; return m_flags & e_FIXED_UP; }
- void SetIsFixedUp() { LIMITED_METHOD_CONTRACT; m_flags |= e_FIXED_UP; }
- PTR_LoaderHeap GetThunkHeap();
- void MarkMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
- BOOL IsMethodFixedUp(COUNT_T iFixup, COUNT_T iMethod);
- };
-
- static IJWFixupData *GetIJWData(void *pBase);
- static PTR_LoaderHeap GetDllThunkHeap(void *pBase);
- static void UnloadIJWModule(void *pBase);
-
-private:
- DWORD m_dwPEKind;
- DWORD m_dwMachine;
- BOOL m_fCachedKindAndMachine;
-
-
-
-public:
- void CachePEKindAndMachine();
- void GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine);
-
};
FORCEINLINE void PEImageRelease(PEImage *i)
diff --git a/src/coreclr/vm/peimage.inl b/src/coreclr/vm/peimage.inl
index b855d379bd31e..8dc72d416fac3 100644
--- a/src/coreclr/vm/peimage.inl
+++ b/src/coreclr/vm/peimage.inl
@@ -106,24 +106,6 @@ inline BOOL PEImage::IsFile()
return !GetPathToLoad().IsEmpty();
}
-#ifndef DACCESS_COMPILE
-inline void PEImage::SetLayout(DWORD dwLayout, PEImageLayout* pLayout)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(dwLayoutHasNTHeaders();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->HasNTHeaders();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->HasNTHeaders();
}
inline BOOL PEImage::HasCorHeader()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->HasCorHeader();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->HasCorHeader();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->HasCorHeader();
}
inline BOOL PEImage::IsComponentAssembly()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->IsComponentAssembly();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->IsComponentAssembly();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->IsComponentAssembly();
}
inline BOOL PEImage::HasReadyToRunHeader()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->HasReadyToRunHeader();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->HasReadyToRunHeader();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->HasReadyToRunHeader();
}
inline BOOL PEImage::HasDirectoryEntry(int entry)
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->HasDirectoryEntry(entry);
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->HasDirectoryEntry(entry);
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->HasDirectoryEntry(entry);
}
inline mdToken PEImage::GetEntryPointToken()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- {
- PTR_PEImageLayout pLayout = GetLoadedLayout();
- if (!pLayout->HasManagedEntryPoint())
- return mdTokenNil;
- return pLayout->GetEntryPointToken();
- }
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- if (!pLayout->HasManagedEntryPoint())
- return mdTokenNil;
- return pLayout->GetEntryPointToken();
- }
+ PEImageLayout* pLayout = GetOrCreateLayout(PEImageLayout::LAYOUT_ANY);
+ if (!pLayout->HasManagedEntryPoint())
+ return mdTokenNil;
+ return pLayout->GetEntryPointToken();
}
inline DWORD PEImage::GetCorHeaderFlags()
{
WRAPPER_NO_CONTRACT;
-
- if (HasLoadedLayout())
- {
- PTR_PEImageLayout pLayout = GetLoadedLayout();
- return VAL32(pLayout->GetCorHeader()->Flags);
- }
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return VAL32(pLayout->GetCorHeader()->Flags);
- }
+ return VAL32(GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->GetCorHeader()->Flags);
}
inline BOOL PEImage::MDImportLoaded()
@@ -299,93 +240,32 @@ inline BOOL PEImage::HasV1Metadata()
inline BOOL PEImage::IsILOnly()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->IsILOnly();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->IsILOnly();
- }
-}
-
-inline WORD PEImage::GetSubsystem()
-{
- WRAPPER_NO_CONTRACT;
- SUPPORTS_DAC;
-
- if (HasLoadedLayout())
- return GetLoadedLayout()->GetSubsystem();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->GetSubsystem();
- }
-}
-
-inline BOOL PEImage::IsDll()
-{
- WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->IsDll();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->IsDll();
- }
-}
-
-inline BOOL PEImage::IsIbcOptimized()
-{
- return false;
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->IsILOnly();
}
inline PTR_CVOID PEImage::GetNativeManifestMetadata(COUNT_T *pSize)
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->GetNativeManifestMetadata(pSize);
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->GetNativeManifestMetadata(pSize);
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->GetNativeManifestMetadata(pSize);
}
inline PTR_CVOID PEImage::GetMetadata(COUNT_T *pSize)
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->GetMetadata(pSize);
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->GetMetadata(pSize);
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->GetMetadata(pSize);
}
inline BOOL PEImage::HasContents()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->HasContents();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->HasContents();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->HasContents();
}
inline CHECK PEImage::CheckFormat()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- CHECK(GetLoadedLayout()->CheckFormat());
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- CHECK(pLayout->CheckFormat());
- }
+ CHECK(GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->CheckFormat());
CHECK_OK;
}
@@ -429,15 +309,13 @@ inline PTR_PEImage PEImage::FindByPath(LPCWSTR pPath, BOOL isInBundle /* = TRUE
DWORD dwHash = CaseHashHelper(pPath, (COUNT_T) wcslen(pPath));
#endif
return (PEImage *) s_Images->LookupValue(dwHash, &locator);
-
}
/* static */
inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags /* = MDInternalImport_Default */, BundleFileLocation bundleFileLocation)
{
- BOOL fUseCache = !((flags & MDInternalImport_NoCache) == MDInternalImport_NoCache);
-
- if (!fUseCache)
+ BOOL forbidCache = (flags & MDInternalImport_NoCache);
+ if (forbidCache)
{
PEImageHolder pImage(new PEImage);
pImage->Init(pPath, bundleFileLocation);
@@ -447,8 +325,6 @@ inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags
CrstHolder holder(&s_hashLock);
PEImage* found = FindByPath(pPath, bundleFileLocation.IsValid());
-
-
if (found == (PEImage*) INVALIDENTRY)
{
// We did not find the entry in the Cache, and we've been asked to only use the cache.
@@ -470,15 +346,8 @@ inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags
}
#endif
-inline BOOL PEImage::IsFileLocked()
-{
- WRAPPER_NO_CONTRACT;
- return (m_pLayouts[IMAGE_FLAT])!=NULL || (m_pLayouts[IMAGE_MAPPED])!=NULL ;
-}
-
#ifndef DACCESS_COMPILE
-
inline void PEImage::AddToHashMap()
{
CONTRACTL
@@ -490,40 +359,30 @@ inline void PEImage::AddToHashMap()
CONTRACTL_END;
_ASSERTE(s_hashLock.OwnedByCurrentThread());
- s_Images->InsertValue(GetIDHash(),this);
+ s_Images->InsertValue(GetPathHash(),this);
m_bInHashMap=TRUE;
}
#endif
-
-
-
inline BOOL PEImage::Has32BitNTHeaders()
{
WRAPPER_NO_CONTRACT;
- if (HasLoadedLayout())
- return GetLoadedLayout()->Has32BitNTHeaders();
- else
- {
- PEImageLayoutHolder pLayout(GetLayout(PEImageLayout::LAYOUT_ANY,LAYOUT_CREATEIFNEEDED));
- return pLayout->Has32BitNTHeaders();
- }
+ return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->Has32BitNTHeaders();
}
-inline BOOL PEImage::HasID()
+inline BOOL PEImage::HasPath()
{
LIMITED_METHOD_CONTRACT;
-
return !GetPath().IsEmpty();
}
-inline ULONG PEImage::GetIDHash()
+inline ULONG PEImage::GetPathHash()
{
CONTRACT(ULONG)
{
- PRECONDITION(HasID());
+ PRECONDITION(HasPath());
MODE_ANY;
GC_NOTRIGGER;
THROWS;
@@ -537,7 +396,7 @@ inline ULONG PEImage::GetIDHash()
#endif
}
-inline void PEImage::CachePEKindAndMachine()
+inline void PEImage::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
{
CONTRACTL
{
@@ -547,40 +406,20 @@ inline void PEImage::CachePEKindAndMachine()
}
CONTRACTL_END;
- // Do nothing if we have cached the information already
- if(m_fCachedKindAndMachine)
- return;
-
- PEImageLayoutHolder pLayout;
- if (HasLoadedLayout())
- {
- pLayout.Assign(GetLoadedLayout(), false);
- }
- else
+ // first check if we have a valid PE kind
+ if (VolatileLoad(&m_dwPEKind) == 0)
{
- pLayout.Assign(GetLayout(PEImageLayout::LAYOUT_MAPPED|PEImageLayout::LAYOUT_FLAT,
- PEImage::LAYOUT_CREATEIFNEEDED));
- }
-
- // Compute result into a local variables first
- DWORD dwPEKind, dwMachine;
- pLayout->GetPEKindAndMachine(&dwPEKind, &dwMachine);
+ // Compute result into a local variables first
+ DWORD dwPEKind, dwMachine;
+ GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->GetPEKindAndMachine(&dwPEKind, &dwMachine);
- // Write the final result into the lock-free cache.
- m_dwPEKind = dwPEKind;
- m_dwMachine = dwMachine;
- MemoryBarrier();
- m_fCachedKindAndMachine = TRUE;
-}
+ // Write the final results - first machine, then kind.
+ m_dwMachine = dwMachine;
+ VolatileStore(&m_dwPEKind, dwPEKind);
+ }
-inline void PEImage::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine)
-{
- WRAPPER_NO_CONTRACT;
- CachePEKindAndMachine();
- if (pdwKind)
- *pdwKind = m_dwPEKind;
- if (pdwMachine)
- *pdwMachine = m_dwMachine;
+ *pdwKind = m_dwPEKind;
+ *pdwMachine = m_dwMachine;
}
#endif // PEIMAGE_INL_
diff --git a/src/coreclr/vm/peimagelayout.cpp b/src/coreclr/vm/peimagelayout.cpp
index 33081b9b60586..e4c4c274cf309 100644
--- a/src/coreclr/vm/peimagelayout.cpp
+++ b/src/coreclr/vm/peimagelayout.cpp
@@ -806,7 +806,7 @@ PEImageLayout::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
WRAPPER_NO_CONTRACT;
DAC_ENUM_VTHIS();
- EMEM_OUT(("MEM: %p PEFile\n", dac_cast(this)));
+ EMEM_OUT(("MEM: %p PEAssembly\n", dac_cast(this)));
PEDecoder::EnumMemoryRegions(flags,false);
}
#endif //DACCESS_COMPILE
diff --git a/src/coreclr/vm/perfinfo.cpp b/src/coreclr/vm/perfinfo.cpp
index b645052f46d2e..667223fedc605 100644
--- a/src/coreclr/vm/perfinfo.cpp
+++ b/src/coreclr/vm/perfinfo.cpp
@@ -27,28 +27,28 @@ PerfInfo::PerfInfo(int pid)
}
// Logs image loads into the process' perfinfo-%d.map file
-void PerfInfo::LogImage(PEFile* pFile, WCHAR* guid)
+void PerfInfo::LogImage(PEAssembly* pPEAssembly, WCHAR* guid)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
- PRECONDITION(pFile != nullptr);
+ PRECONDITION(pPEAssembly != nullptr);
PRECONDITION(guid != nullptr);
} CONTRACTL_END;
SString value;
- const SString& path = pFile->GetPath();
+ const SString& path = pPEAssembly->GetPath();
if (path.IsEmpty())
{
return;
}
SIZE_T baseAddr = 0;
- if (pFile->IsReadyToRun())
+ if (pPEAssembly->IsReadyToRun())
{
- PEImageLayout *pLoadedLayout = pFile->GetLoaded();
+ PEImageLayout *pLoadedLayout = pPEAssembly->GetLoadedLayout();
if (pLoadedLayout)
{
baseAddr = (SIZE_T)pLoadedLayout->GetBase();
diff --git a/src/coreclr/vm/perfinfo.h b/src/coreclr/vm/perfinfo.h
index 759a844f30925..16b06865925c6 100644
--- a/src/coreclr/vm/perfinfo.h
+++ b/src/coreclr/vm/perfinfo.h
@@ -22,7 +22,7 @@ class PerfInfo {
public:
PerfInfo(int pid);
~PerfInfo();
- void LogImage(PEFile* pFile, WCHAR* guid);
+ void LogImage(PEAssembly* pPEAssembly, WCHAR* guid);
private:
CFileStream* m_Stream;
diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp
index 31da16cac5586..48f178aeb67c3 100644
--- a/src/coreclr/vm/perfmap.cpp
+++ b/src/coreclr/vm/perfmap.cpp
@@ -219,22 +219,22 @@ void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, cons
}
-void PerfMap::LogImageLoad(PEFile * pFile)
+void PerfMap::LogImageLoad(PEAssembly * pPEAssembly)
{
if (s_enabled)
{
- s_Current->LogImage(pFile);
+ s_Current->LogImage(pPEAssembly);
}
}
// Log an image load to the map.
-void PerfMap::LogImage(PEFile * pFile)
+void PerfMap::LogImage(PEAssembly * pPEAssembly)
{
CONTRACTL{
THROWS;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
- PRECONDITION(pFile != nullptr);
+ PRECONDITION(pPEAssembly != nullptr);
} CONTRACTL_END;
@@ -247,9 +247,9 @@ void PerfMap::LogImage(PEFile * pFile)
EX_TRY
{
WCHAR wszSignature[39];
- GetNativeImageSignature(pFile, wszSignature, lengthof(wszSignature));
+ GetNativeImageSignature(pPEAssembly, wszSignature, lengthof(wszSignature));
- m_PerfInfo->LogImage(pFile, wszSignature);
+ m_PerfInfo->LogImage(pPEAssembly, wszSignature);
}
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}
@@ -361,10 +361,10 @@ void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode,
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}
-void PerfMap::GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize)
+void PerfMap::GetNativeImageSignature(PEAssembly * pPEAssembly, WCHAR * pwszSig, unsigned int nSigSize)
{
CONTRACTL{
- PRECONDITION(pFile != nullptr);
+ PRECONDITION(pPEAssembly != nullptr);
PRECONDITION(pwszSig != nullptr);
PRECONDITION(nSigSize >= 39);
} CONTRACTL_END;
@@ -372,7 +372,7 @@ void PerfMap::GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned
// We use the MVID as the signature, since ready to run images
// don't have a native image signature.
GUID mvid;
- pFile->GetMVID(&mvid);
+ pPEAssembly->GetMVID(&mvid);
if(!StringFromGUID2(mvid, pwszSig, nSigSize))
{
pwszSig[0] = '\0';
@@ -417,7 +417,7 @@ void NativeImagePerfMap::LogDataForModule(Module * pModule)
{
STANDARD_VM_CONTRACT;
- PEImageLayout * pLoadedLayout = pModule->GetFile()->GetLoaded();
+ PEImageLayout * pLoadedLayout = pModule->GetPEAssembly()->GetLoadedLayout();
_ASSERTE(pLoadedLayout != nullptr);
ReadyToRunInfo::MethodIterator mi(pModule->GetReadyToRunInfo());
diff --git a/src/coreclr/vm/perfmap.h b/src/coreclr/vm/perfmap.h
index 14595813877d8..587a776e68276 100644
--- a/src/coreclr/vm/perfmap.h
+++ b/src/coreclr/vm/perfmap.h
@@ -57,17 +57,17 @@ class PerfMap
void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier);
// Does the actual work to log an image
- void LogImage(PEFile * pFile);
+ void LogImage(PEAssembly * pPEAssembly);
// Get the image signature and store it as a string.
- static void GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize);
+ static void GetNativeImageSignature(PEAssembly * pPEAssembly, WCHAR * pwszSig, unsigned int nSigSize);
public:
// Initialize the map for the current process.
static void Initialize();
// Log a native image load to the map.
- static void LogImageLoad(PEFile * pFile);
+ static void LogImageLoad(PEAssembly * pPEAssembly);
// Log a JIT compiled method to the map.
static void LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, PrepareCodeConfig *pConfig);
diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
index 4f08f247da765..5c47a34f70487 100644
--- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp
+++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
@@ -2131,7 +2131,7 @@ HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
// Yay!
EE_THREAD_NOT_REQUIRED;
- // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
+ // PEAssembly::GetRWImporter and GetReadablePublicMetaDataInterface take locks
CAN_TAKE_LOCK;
}
@@ -3977,11 +3977,11 @@ DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
}
CONTRACTL_END;
- PEFile * pPEFile = pModule->GetFile();
- if (pPEFile == NULL)
+ PEAssembly * pPEAssembly = pModule->GetPEAssembly();
+ if (pPEAssembly == NULL)
{
// Hopefully this should never happen; but just in case, don't try to determine the
- // flags without a PEFile.
+ // flags without a PEAssembly.
return 0;
}
@@ -3996,15 +3996,15 @@ DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
}
#endif
- // Not NGEN or ReadyToRun.
- if (pPEFile->HasOpenedILimage())
+ // Not Dynamic.
+ if (pPEAssembly->HasPEImage())
{
- PEImage * pILImage = pPEFile->GetOpenedILimage();
+ PEImage * pILImage = pPEAssembly->GetPEImage();
if (pILImage->IsFile())
{
dwRet |= COR_PRF_MODULE_DISK;
}
- if (pPEFile->GetLoadedIL()->IsFlat())
+ if (pPEAssembly->GetLoadedLayout()->IsFlat())
{
dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
}
@@ -4020,11 +4020,6 @@ DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
dwRet |= COR_PRF_MODULE_COLLECTIBLE;
}
- if (pModule->IsResource())
- {
- dwRet |= COR_PRF_MODULE_RESOURCE;
- }
-
return dwRet;
}
@@ -4086,7 +4081,7 @@ HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID moduleId,
EX_TRY
{
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pFile = pModule->GetPEAssembly();
// Pick some safe defaults to begin with.
if (ppBaseLoadAddress != NULL)
@@ -4209,7 +4204,7 @@ HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId,
// but we might be able to lift that restriction and make this be
// EE_THREAD_NOT_REQUIRED.
- // PEFile::GetRWImporter & PEFile::GetEmitter &
+ // PEAssembly::GetRWImporter & PEAssembly::GetEmitter &
// GetReadablePublicMetaDataInterface take locks
CAN_TAKE_LOCK;
@@ -4244,14 +4239,6 @@ HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId,
return CORPROF_E_DATAINCOMPLETE;
}
- // Make sure we can get the importer first
- if (pModule->IsResource())
- {
- if (ppOut)
- *ppOut = NULL;
- return S_FALSE;
- }
-
// Decide which type of open mode we are in to see which you require.
if ((dwOpenFlags & ofWrite) == 0)
{
@@ -4299,7 +4286,7 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
// Yay!
MODE_ANY;
- // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
+ // Module::GetDynamicIL both take a lock
CAN_TAKE_LOCK;
}
@@ -4337,9 +4324,9 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
IMDInternalImport *pImport = pModule->GetMDImport();
_ASSERTE(pImport);
- PEFile *pFile = pModule->GetFile();
+ PEAssembly *pPEAssembly = pModule->GetPEAssembly();
- if (!pFile->CheckLoaded())
+ if (!pPEAssembly->HasLoadedPEImage())
return (CORPROF_E_DATAINCOMPLETE);
LPCBYTE pbMethod = NULL;
@@ -4354,7 +4341,7 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
// Check to see if the method has associated IL
- if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
+ if ((RVA == 0 && !pPEAssembly->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
{
return (CORPROF_E_FUNCTION_NOT_IL);
}
@@ -4449,7 +4436,7 @@ HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID modul
Module * pModule = (Module *) moduleId;
if (pModule->IsBeingUnloaded() ||
- !pModule->GetFile()->CheckLoaded())
+ !pModule->GetPEAssembly()->HasLoadedPEImage())
{
return (CORPROF_E_DATAINCOMPLETE);
}
@@ -4472,7 +4459,7 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
{
CONTRACTL
{
- // PEFile::GetEmitter, Module::SetDynamicIL all throw
+ // PEAssembly::GetEmitter, Module::SetDynamicIL all throw
THROWS;
// Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
@@ -4482,7 +4469,7 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
// Yay!
MODE_ANY;
- // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
+ // Module::SetDynamicIL & PEAssembly::GetEmitter take locks
CAN_TAKE_LOCK;
}
diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp
index 4a6052b1ef162..bf77758eeccdf 100644
--- a/src/coreclr/vm/readytoruninfo.cpp
+++ b/src/coreclr/vm/readytoruninfo.cpp
@@ -392,7 +392,7 @@ BOOL ReadyToRunInfo::IsReadyToRunEnabled()
// Any other value: Handle of the log file.
static FILE * volatile s_r2rLogFile = (FILE *)(-1);
-static void LogR2r(const char *msg, PEFile *pFile)
+static void LogR2r(const char *msg, PEAssembly *pPEAssembly)
{
STANDARD_VM_CONTRACT;
@@ -430,7 +430,7 @@ static void LogR2r(const char *msg, PEFile *pFile)
if (r2rLogFile == NULL)
return;
- fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
+ fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pPEAssembly->GetPath().GetUnicode());
fflush(r2rLogFile);
}
@@ -503,7 +503,7 @@ static NativeImage *AcquireCompositeImage(Module * pModule, PEImageLayout * pLay
if (ownerCompositeExecutableName != NULL)
{
- AssemblyBinder *binder = pModule->GetFile()->GetAssemblyBinder();
+ AssemblyBinder *binder = pModule->GetPEAssembly()->GetAssemblyBinder();
return binder->LoadNativeImage(pModule, ownerCompositeExecutableName);
}
@@ -514,7 +514,7 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker
{
STANDARD_VM_CONTRACT;
- PEFile * pFile = pModule->GetFile();
+ PEAssembly * pFile = pModule->GetPEAssembly();
if (!IsReadyToRunEnabled())
{
@@ -529,13 +529,13 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker
return NULL;
}
- if (!pFile->HasLoadedIL())
+ if (!pFile->HasLoadedPEImage())
{
- DoLog("Ready to Run disabled - no loaded IL image");
+ DoLog("Ready to Run disabled - no loaded PE image");
return NULL;
}
- PEImageLayout * pLayout = pFile->GetLoadedIL();
+ PEImageLayout * pLayout = pFile->GetLoadedLayout();
if (!pLayout->HasReadyToRunHeader())
{
DoLog("Ready to Run header not found");
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index 620ead8289e4f..5c436a73c9000 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -2728,7 +2728,7 @@ void QCALLTYPE ModuleHandle::GetPEKind(QCall::ModuleHandle pModule, DWORD* pdwPE
QCALL_CONTRACT;
BEGIN_QCALL;
- pModule->GetFile()->GetPEKindAndMachine(pdwPEKind, pdwMachine);
+ pModule->GetPEAssembly()->GetPEKindAndMachine(pdwPEKind, pdwMachine);
END_QCALL;
}
@@ -2742,10 +2742,6 @@ FCIMPL1(INT32, ModuleHandle::GetMDStreamVersion, ReflectModuleBaseObject * pModu
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
Module *pModule = refModule->GetModule();
-
- if (pModule->IsResource())
- return 0;
-
return pModule->GetMDImport()->GetMetadataStreamVersion();
}
FCIMPLEND
@@ -2787,10 +2783,6 @@ FCIMPL1(INT32, ModuleHandle::GetToken, ReflectModuleBaseObject * pModuleUNSAFE)
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
Module *pModule = refModule->GetModule();
-
- if (pModule->IsResource())
- return mdModuleNil;
-
return pModule->GetMDImport()->GetModuleFromScope();
}
FCIMPLEND
@@ -2805,10 +2797,6 @@ FCIMPL1(IMDInternalImport*, ModuleHandle::GetMetadataImport, ReflectModuleBaseOb
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
Module *pModule = refModule->GetModule();
-
- if (pModule->IsResource())
- return NULL;
-
return pModule->GetMDImport();
}
FCIMPLEND
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index a3aea61ba7b2b..4c438360513cb 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -3547,7 +3547,7 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModu
#ifdef DACCESS_COMPILE
ThrowHR(hr);
#else
- EEFileLoadException::Throw(pModule2->GetFile(), hr);
+ EEFileLoadException::Throw(pModule2->GetPEAssembly(), hr);
#endif //!DACCESS_COMPILE
} // CompareTypeTokens
diff --git a/src/coreclr/vm/typeparse.cpp b/src/coreclr/vm/typeparse.cpp
index 84ce7124c473c..258b50d86916b 100644
--- a/src/coreclr/vm/typeparse.cpp
+++ b/src/coreclr/vm/typeparse.cpp
@@ -1415,7 +1415,7 @@ TypeName::GetTypeHaveAssemblyHelper(
if (pManifestModule->LookupFile(mdFile))
continue;
- pManifestModule->LoadModule(GetAppDomain(), mdFile, FALSE);
+ pManifestModule->LoadModule(GetAppDomain(), mdFile);
th = GetTypeHaveAssemblyHelper(pAssembly, bThrowIfNotFound, bIgnoreCase, NULL, FALSE);
@@ -1479,7 +1479,7 @@ DomainAssembly * LoadDomainAssembly(
{
// If the requesting assembly has Fallback LoadContext binder available,
// then set it up in the AssemblySpec.
- PEFile *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile();
+ PEAssembly *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile();
spec.SetFallbackBinderForRequestingAssembly(pRequestingAssemblyManifestFile->GetFallbackBinder());
}
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
index 3d070f437073b..711bc0d4ae5a3 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
@@ -218,6 +218,7 @@
+
@@ -237,7 +238,7 @@
-
+
sharedhost
Dotnet_CLI_SharedHost
HostSrc
+ afterInstallExecute
false
true
sharedhost
diff --git a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
index aaabf8e571bcd..d9feb540d70bc 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs
@@ -461,6 +461,52 @@ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only()
}
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Multi-level lookup is only supported on Windows.
+ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only_self_register_program_files()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+
+ string expectedFrameworkNames = string.Join(';', new[]
+ {
+ "HostFxr.Test.A",
+ "HostFxr.Test.A",
+ "HostFxr.Test.B",
+ });
+
+ string expectedFrameworkVersions = string.Join(';', new[]
+ {
+ "1.2.3",
+ "3.0.0",
+ "5.6.7-A",
+ });
+
+ string expectedFrameworkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.B"),
+ });
+
+ using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath))
+ {
+ // We pass f.WorkingDir so that we don't resolve dotnet_dir to the global installation
+ // in the native side.
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", f.WorkingDir })
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles)
+ // Test with a self-registered path the same as ProgramFiles, with a trailing slash. Expect this to be de-duped
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", Path.Combine(f.ProgramFiles, "dotnet") + Path.DirectorySeparatorChar)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework names:[{expectedFrameworkNames}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework versions:[{expectedFrameworkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework paths:[{expectedFrameworkPaths}]");
+ }
+ }
+
[Fact]
public void Hostfxr_get_dotnet_environment_info_global_install_path()
{
diff --git a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
index 8dcef20c22dea..73a3fda2b55fd 100644
--- a/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
+++ b/src/installer/tests/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs
index c1abefa490d75..42020d9217b9a 100644
--- a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs
+++ b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Cipher.cs
@@ -15,7 +15,6 @@ internal static extern SafeEvpCipherCtxHandle EvpCipherCreate(
IntPtr cipher,
ref byte key,
int keyLength,
- int effectivekeyLength,
ref byte iv,
int enc);
diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs
index d6ac21cf3219f..051b412b1199d 100644
--- a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs
+++ b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs
@@ -98,7 +98,7 @@ public static void StopProfile()
{
}
- // Called by the AOT profiler to save profile data into Module.aot_profile_data
+ // Called by the AOT profiler to save profile data into INTERNAL.aot_profile_data
[MethodImplAttribute(MethodImplOptions.NoInlining)]
public static unsafe void DumpAotProfileData(ref byte buf, int len, string extraArg)
{
diff --git a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
index f38bb375b347e..7fbaf9cc32eab 100644
--- a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
+++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs
@@ -136,8 +136,9 @@ static Ldap()
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)]
public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue);
+ // Note that ldap_start_tls_s has a different signature across Windows LDAP and OpenLDAP
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_start_tls_s", CharSet = CharSet.Ansi)]
- public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls);
+ public static extern int ldap_start_tls(ConnectionHandle ldapHandle, IntPtr serverControls, IntPtr clientControls);
[DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_result", CharSet = CharSet.Ansi)]
public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt);
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Cipher.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Cipher.cs
index f960ed7e881c5..ce77602722126 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Cipher.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Cipher.cs
@@ -14,7 +14,6 @@ internal static partial SafeEvpCipherCtxHandle EvpCipherCreate(
IntPtr cipher,
ref byte key,
int keyLength,
- int effectivekeyLength,
ref byte iv,
int enc);
diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/RC2BCryptModes.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/RC2BCryptModes.cs
index 7c7503b8b9cb0..5caf5f0c8da7e 100644
--- a/src/libraries/Common/src/Interop/Windows/BCrypt/RC2BCryptModes.cs
+++ b/src/libraries/Common/src/Interop/Windows/BCrypt/RC2BCryptModes.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Diagnostics;
using System.Security.Cryptography;
using Internal.NativeCrypto;
@@ -26,10 +27,8 @@ private static SafeAlgorithmHandle OpenRC2Algorithm(string cipherMode, int effec
SafeAlgorithmHandle hAlg = Cng.BCryptOpenAlgorithmProvider(Cng.BCRYPT_RC2_ALGORITHM, null, Cng.OpenAlgorithmProviderFlags.NONE);
hAlg.SetCipherMode(cipherMode);
- if (effectiveKeyLength != 0)
- {
- Cng.SetEffectiveKeyLength(hAlg, effectiveKeyLength);
- }
+ Debug.Assert(effectiveKeyLength > 0);
+ Cng.SetEffectiveKeyLength(hAlg, effectiveKeyLength);
return hAlg;
}
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Interop/Windows/Crypt32/Interop.CertDuplicateCertificateContext.cs b/src/libraries/Common/src/Interop/Windows/Crypt32/Interop.CertDuplicateCertificateContext_IntPtr.cs
similarity index 100%
rename from src/libraries/System.Security.Cryptography.Pkcs/src/Interop/Windows/Crypt32/Interop.CertDuplicateCertificateContext.cs
rename to src/libraries/Common/src/Interop/Windows/Crypt32/Interop.CertDuplicateCertificateContext_IntPtr.cs
diff --git a/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs b/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs
index ad087304b4e5a..7e7afcec97a72 100644
--- a/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs
+++ b/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs
@@ -9,11 +9,7 @@
using System.IO;
using System.Text;
-#if MS_IO_REDIST
-namespace Microsoft.IO
-#else
namespace System.IO
-#endif
{
internal static partial class FileSystem
{
diff --git a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs
index 821f878796e84..dba07a8fb4156 100644
--- a/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs
+++ b/src/libraries/Common/src/System/IO/FileSystem.DirectoryCreation.Windows.cs
@@ -9,11 +9,7 @@
using System.IO;
using System.Text;
-#if MS_IO_REDIST
-namespace Microsoft.IO
-#else
namespace System.IO
-#endif
{
internal static partial class FileSystem
{
diff --git a/src/libraries/Common/src/System/IO/PathInternal.CaseSensitivity.cs b/src/libraries/Common/src/System/IO/PathInternal.CaseSensitivity.cs
index 80fc6b43ff607..32769debc29d1 100644
--- a/src/libraries/Common/src/System/IO/PathInternal.CaseSensitivity.cs
+++ b/src/libraries/Common/src/System/IO/PathInternal.CaseSensitivity.cs
@@ -3,10 +3,6 @@
using System.Diagnostics;
-#if MS_IO_REDIST
-using Microsoft.IO;
-#endif
-
namespace System.IO
{
/// Contains internal path helpers that are shared between many projects.
@@ -28,11 +24,7 @@ internal static bool IsCaseSensitive
{
get
{
-#if MS_IO_REDIST
- return false; // Windows is always case-insensitive
-#else
return !(OperatingSystem.IsWindows() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS());
-#endif
}
}
}
diff --git a/src/libraries/Common/src/System/IO/PathInternal.cs b/src/libraries/Common/src/System/IO/PathInternal.cs
index ff9d79caee253..52aaa59072dd7 100644
--- a/src/libraries/Common/src/System/IO/PathInternal.cs
+++ b/src/libraries/Common/src/System/IO/PathInternal.cs
@@ -15,13 +15,8 @@ internal static partial class PathInternal
///
internal static bool StartsWithDirectorySeparator(ReadOnlySpan path) => path.Length > 0 && IsDirectorySeparator(path[0]);
-#if MS_IO_REDIST
- internal static string EnsureTrailingSeparator(string path)
- => EndsInDirectorySeparator(path) ? path : path + DirectorySeparatorCharAsString;
-#else
internal static string EnsureTrailingSeparator(string path)
=> EndsInDirectorySeparator(path.AsSpan()) ? path : path + DirectorySeparatorCharAsString;
-#endif
internal static bool IsRoot(ReadOnlySpan path)
=> path.Length == GetRootLength(path);
@@ -248,10 +243,6 @@ internal static bool EndsInDirectorySeparator(ReadOnlySpan path) =>
internal static string GetLinkTargetFullPath(string path, string pathToTarget)
=> IsPartiallyQualified(pathToTarget.AsSpan()) ?
-#if MS_IO_REDIST
- Path.Combine(Path.GetDirectoryName(path), pathToTarget) : pathToTarget;
-#else
Path.Join(Path.GetDirectoryName(path.AsSpan()), pathToTarget.AsSpan()) : pathToTarget;
-#endif
}
}
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
index 346098414b39b..9491c563668f7 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
@@ -358,6 +358,54 @@ private HttpRequestData ParseHeaders(ReadOnlySpan buffer)
}
public async Task WaitForCancellationAsync(bool ignoreIncomingData = true)
+ {
+ bool readCanceled = false;
+ bool writeCanceled = false;
+
+ async Task WaitForReadCancellation()
+ {
+ try
+ {
+ if (ignoreIncomingData)
+ {
+ await DrainResponseData();
+ }
+ else
+ {
+ int bytesRead = await _stream.ReadAsync(new byte[1]);
+ if (bytesRead != 0)
+ {
+ throw new Exception($"Unexpected data received while waiting for client cancllation.");
+ }
+ }
+ }
+ catch (QuicStreamAbortedException ex) when (ex.ErrorCode == Http3LoopbackConnection.H3_REQUEST_CANCELLED)
+ {
+ readCanceled = true;
+ }
+ }
+
+ async Task WaitForWriteCancellation()
+ {
+ try
+ {
+ await _stream.WaitForWriteCompletionAsync();
+ }
+ catch (QuicStreamAbortedException ex) when (ex.ErrorCode == Http3LoopbackConnection.H3_REQUEST_CANCELLED)
+ {
+ writeCanceled = true;
+ }
+ }
+
+ await Task.WhenAll(WaitForReadCancellation(), WaitForWriteCancellation());
+
+ if (!readCanceled && !writeCanceled)
+ {
+ throw new Exception("Both read and write completed successfully; expected clien cancellation");
+ }
+ }
+
+ private async Task DrainResponseData()
{
while (true)
{
@@ -368,11 +416,10 @@ public async Task WaitForCancellationAsync(bool ignoreIncomingData = true)
case null:
// end of stream reached.
return;
- case DataFrame when ignoreIncomingData == true:
+ case DataFrame:
break;
default:
- Debug.Fail("Unexpected frame type while waiting for client cancellation.");
- throw new Exception();
+ throw new Exception($"Unexpected frame type {frameType} while draining response data.");
}
}
}
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs
index c90753dd4025d..1587fc46dc6b4 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs
@@ -226,6 +226,7 @@ public async Task NoCallback_BadCertificate_ThrowsException(string url)
[OuterLoop("Uses external servers")]
[ConditionalFact(nameof(ClientSupportsDHECipherSuites))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60190")]
public async Task NoCallback_RevokedCertificate_NoRevocationChecking_Succeeds()
{
using (HttpClient client = CreateHttpClient())
diff --git a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs
index f6cc44f67e7c9..60153c0b4975d 100644
--- a/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs
+++ b/src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs
@@ -227,7 +227,43 @@ await client.GetAsync(remoteServer.EchoUri, HttpCompletionOption.ResponseHeaders
}
}
}
+
#if NETCOREAPP
+ [OuterLoop]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))]
+ public async Task BrowserHttpHandler_Streaming()
+ {
+ var WebAssemblyEnableStreamingResponseKey = new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse");
+
+ var size = 1500 * 1024 * 1024;
+ var req = new HttpRequestMessage(HttpMethod.Get, Configuration.Http.RemoteSecureHttp11Server.BaseUri + "large.ashx?size=" + size);
+
+ req.Options.Set(WebAssemblyEnableStreamingResponseKey, true);
+
+ using (HttpClient client = CreateHttpClientForRemoteServer(Configuration.Http.RemoteSecureHttp11Server))
+ // we need to switch off Response buffering of default ResponseContentRead option
+ using (HttpResponseMessage response = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead))
+ {
+ Assert.Equal(typeof(StreamContent), response.Content.GetType());
+
+ Assert.Equal("application/octet-stream", response.Content.Headers.ContentType.MediaType);
+ Assert.True(size == response.Content.Headers.ContentLength, "ContentLength");
+
+ var stream = await response.Content.ReadAsStreamAsync();
+ Assert.Equal("ReadOnlyStream", stream.GetType().Name);
+ var buffer = new byte[1024 * 1024];
+ int totalCount = 0;
+ int fetchedCount = 0;
+ do
+ {
+ // with WebAssemblyEnableStreamingResponse option set, we will be using https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read
+ fetchedCount = await stream.ReadAsync(buffer, 0, buffer.Length);
+ totalCount += fetchedCount;
+ } while (fetchedCount != 0);
+ Assert.Equal(size, totalCount);
+ }
+ }
+
[Theory]
[InlineData(TransferType.ContentLength, TransferError.ContentLengthTooLarge)]
[InlineData(TransferType.Chunked, TransferError.MissingChunkTerminator)]
diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs
index f129157b1d916..846a30fd9951e 100644
--- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs
+++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs
@@ -83,6 +83,11 @@ public async Task Invoke(HttpContext context)
await TestHandler.InvokeAsync(context);
return;
}
+ if (path.Equals(new PathString("/large.ashx")))
+ {
+ await LargeResponseHandler.InvokeAsync(context);
+ return;
+ }
// Default handling.
await EchoHandler.InvokeAsync(context);
diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/LargeResponse.cs b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/LargeResponse.cs
new file mode 100644
index 0000000000000..41e21fd3cb5eb
--- /dev/null
+++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/LargeResponse.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+
+namespace NetCoreServer
+{
+ public class LargeResponseHandler
+ {
+ public static async Task InvokeAsync(HttpContext context)
+ {
+ RequestHelper.AddResponseCookies(context);
+
+ if (!AuthenticationHelper.HandleAuthentication(context))
+ {
+ return;
+ }
+
+ // Add original request method verb as a custom response header.
+ context.Response.Headers.Add("X-HttpRequest-Method", context.Request.Method);
+
+ var size = 1024;
+ if (context.Request.Query.TryGetValue("size", out var value))
+ {
+ size = Int32.Parse(value);
+ }
+ context.Response.ContentType = "application/octet-stream";
+ context.Response.ContentLength = size;
+ const int bufferSize = 1024 * 100;
+ var bytes = new byte[bufferSize];
+ Random.Shared.NextBytes(bytes);
+ var remaining = size;
+ while (remaining > 0)
+ {
+ var send = Math.Min(remaining, bufferSize);
+ await context.Response.Body.WriteAsync(bytes, 0, send);
+ remaining -= send;
+ }
+ }
+ }
+}
diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj
index 875277b02d31a..d5c11a7905ae9 100644
--- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj
+++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj
@@ -18,6 +18,7 @@
+
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
index 77496e80d24c7..c4e2e657c07ab 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
@@ -48,6 +48,8 @@ public static partial class PlatformDetection
public static bool IsNotArm64Process => !IsArm64Process;
public static bool IsArmOrArm64Process => IsArmProcess || IsArm64Process;
public static bool IsNotArmNorArm64Process => !IsArmOrArm64Process;
+ public static bool IsX86Process => RuntimeInformation.ProcessArchitecture == Architecture.X86;
+ public static bool IsNotX86Process => !IsX86Process;
public static bool IsArgIteratorSupported => IsMonoRuntime || (IsWindows && IsNotArmProcess);
public static bool IsArgIteratorNotSupported => !IsArgIteratorSupported;
public static bool Is32BitProcess => IntPtr.Size == 4;
@@ -312,12 +314,6 @@ private static Version GetICUVersion()
version & 0xFF);
}
- private static readonly Lazy _net5CompatFileStream = new Lazy(() => GetStaticNonPublicBooleanPropertyValue("System.IO.Strategies.FileStreamHelpers", "UseNet5CompatStrategy"));
-
- public static bool IsNet5CompatFileStreamEnabled => _net5CompatFileStream.Value;
-
- public static bool IsNet5CompatFileStreamDisabled => !IsNet5CompatFileStreamEnabled;
-
private static readonly Lazy s_fileLockingDisabled = new Lazy(() => GetStaticNonPublicBooleanPropertyValue("Microsoft.Win32.SafeHandles.SafeFileHandle", "DisableFileLocking"));
public static bool IsFileLockingEnabled => IsWindows || !s_fileLockingDisabled.Value;
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
index f13edb1872ebe..2cbcfbb1c089e 100644
--- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
@@ -248,19 +248,17 @@ private static void BindProperty(PropertyInfo property, object instance, IConfig
return;
}
- object propertyValue = property.GetValue(instance);
bool hasSetter = property.SetMethod != null && (property.SetMethod.IsPublic || options.BindNonPublicProperties);
- if (propertyValue == null && !hasSetter)
+ if (!hasSetter)
{
- // Property doesn't have a value and we cannot set it so there is no
- // point in going further down the graph
+ // The property cannot be set so there is no point going further
return;
}
- propertyValue = GetPropertyValue(property, instance, config, options);
+ object propertyValue = GetPropertyValue(property, instance, config, options);
- if (propertyValue != null && hasSetter)
+ if (propertyValue != null)
{
property.SetValue(instance, propertyValue);
}
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
index c5dbd9d90821a..6629557ce89be 100644
--- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/ConfigurationBinderTests.cs
@@ -117,6 +117,11 @@ public class ByteArrayOptions
public byte[] MyByteArray { get; set; }
}
+ public class GetterOnlyOptions
+ {
+ public string MyString => throw new NotImplementedException();
+ }
+
[Fact]
public void CanBindIConfigurationSection()
{
@@ -343,6 +348,20 @@ public void ThrowsIfPropertyInConfigMissingInNestedModel()
Assert.Equal(expectedMessage, ex.Message);
}
+ [Fact]
+ public void DoesNotExecuteGetterIfNoSetter()
+ {
+ var dic = new Dictionary
+ {
+ {"MyString", "hello world"}
+ };
+ var configurationBuilder = new ConfigurationBuilder();
+ configurationBuilder.AddInMemoryCollection(dic);
+ var config = configurationBuilder.Build();
+
+ var _ = config.Get();
+ }
+
[Fact]
public void GetDefaultsWhenDataDoesNotExist()
{
diff --git a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs
index feef64fc2dde1..c9719bcdbbc92 100644
--- a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs
+++ b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs
@@ -15,23 +15,24 @@ public partial class ChainedConfigurationProvider : Microsoft.Extensions.Configu
{
public ChainedConfigurationProvider(Microsoft.Extensions.Configuration.ChainedConfigurationSource source) { }
public void Dispose() { }
- public System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string parentPath) { throw null; }
+ public System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string? parentPath) { throw null; }
public Microsoft.Extensions.Primitives.IChangeToken GetReloadToken() { throw null; }
public void Load() { }
- public void Set(string key, string value) { }
- public bool TryGet(string key, out string value) { throw null; }
+ public void Set(string key, string? value) { }
+ public bool TryGet(string key, out string? value) { throw null; }
}
public partial class ChainedConfigurationSource : Microsoft.Extensions.Configuration.IConfigurationSource
{
public ChainedConfigurationSource() { }
- public Microsoft.Extensions.Configuration.IConfiguration Configuration { get { throw null; } set { } }
+ [System.Diagnostics.CodeAnalysis.DisallowNull]
+ public Microsoft.Extensions.Configuration.IConfiguration? Configuration { get { throw null; } set { } }
public bool ShouldDisposeConfiguration { get { throw null; } set { } }
public Microsoft.Extensions.Configuration.IConfigurationProvider Build(Microsoft.Extensions.Configuration.IConfigurationBuilder builder) { throw null; }
}
public sealed partial class ConfigurationManager : Microsoft.Extensions.Configuration.IConfigurationBuilder, Microsoft.Extensions.Configuration.IConfigurationRoot, System.IDisposable
{
public ConfigurationManager() { }
- public string this[string key] { get { throw null; } set { throw null; } }
+ public string? this[string key] { get { throw null; } set { throw null; } }
public IConfigurationSection GetSection(string key) { throw null; }
public System.Collections.Generic.IEnumerable GetChildren() { throw null; }
public void Dispose() { throw null; }
@@ -55,19 +56,19 @@ public partial class ConfigurationKeyComparer : System.Collections.Generic.IComp
{
public ConfigurationKeyComparer() { }
public static Microsoft.Extensions.Configuration.ConfigurationKeyComparer Instance { get { throw null; } }
- public int Compare(string x, string y) { throw null; }
+ public int Compare(string? x, string? y) { throw null; }
}
public abstract partial class ConfigurationProvider : Microsoft.Extensions.Configuration.IConfigurationProvider
{
protected ConfigurationProvider() { }
- protected System.Collections.Generic.IDictionary Data { get { throw null; } set { } }
- public virtual System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string parentPath) { throw null; }
+ protected System.Collections.Generic.IDictionary Data { get { throw null; } set { } }
+ public virtual System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string? parentPath) { throw null; }
public Microsoft.Extensions.Primitives.IChangeToken GetReloadToken() { throw null; }
public virtual void Load() { }
protected void OnReload() { }
- public virtual void Set(string key, string value) { }
+ public virtual void Set(string key, string? value) { }
public override string ToString() { throw null; }
- public virtual bool TryGet(string key, out string value) { throw null; }
+ public virtual bool TryGet(string key, out string? value) { throw null; }
}
public partial class ConfigurationReloadToken : Microsoft.Extensions.Primitives.IChangeToken
{
@@ -75,12 +76,12 @@ public ConfigurationReloadToken() { }
public bool ActiveChangeCallbacks { get { throw null; } }
public bool HasChanged { get { throw null; } }
public void OnReload() { }
- public System.IDisposable RegisterChangeCallback(System.Action
-
diff --git a/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/StringExtensions.cs b/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/StringExtensions.cs
deleted file mode 100644
index fbe320a857ca0..0000000000000
--- a/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/StringExtensions.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Runtime.CompilerServices;
-
-namespace Microsoft.IO
-{
- public static class StringExtensions
- {
- public delegate void SpanAction(Span span, TArg arg);
-
- public static bool Contains(this string s, char value)
- {
- return s.IndexOf(value) != -1;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static bool EqualsOrdinal(this ReadOnlySpan span, ReadOnlySpan value)
- {
- if (span.Length != value.Length)
- return false;
- if (value.Length == 0) // span.Length == value.Length == 0
- return true;
- return span.SequenceEqual(value);
- }
-
- public static unsafe string Create(int length, TState state, SpanAction action)
- {
- if (action == null)
- throw new ArgumentNullException(nameof(action));
-
- if (length <= 0)
- {
- if (length == 0)
- return string.Empty;
- throw new ArgumentOutOfRangeException(nameof(length));
- }
-
- string result = new string('\0', length);
- fixed (char* r = result)
- {
- action(new Span(r, length), state);
- }
- return result;
- }
-
- internal static unsafe string Concat(ReadOnlySpan str0, ReadOnlySpan str1)
- {
- var result = new string('\0', checked(str0.Length + str1.Length));
- fixed (char* resultPtr = result)
- {
- var resultSpan = new Span(resultPtr, result.Length);
-
- str0.CopyTo(resultSpan);
- str1.CopyTo(resultSpan.Slice(str0.Length));
- }
- return result;
- }
-
- internal static unsafe string Concat(ReadOnlySpan str0, ReadOnlySpan str1, ReadOnlySpan str2)
- {
- var result = new string('\0', checked(str0.Length + str1.Length + str2.Length));
- fixed (char* resultPtr = result)
- {
- var resultSpan = new Span(resultPtr, result.Length);
-
- str0.CopyTo(resultSpan);
- resultSpan = resultSpan.Slice(str0.Length);
-
- str1.CopyTo(resultSpan);
- resultSpan = resultSpan.Slice(str1.Length);
-
- str2.CopyTo(resultSpan);
- }
- return result;
- }
- }
-}
diff --git a/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/ThrowHelper.cs b/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/ThrowHelper.cs
deleted file mode 100644
index 31e3766c51494..0000000000000
--- a/src/libraries/Microsoft.IO.Redist/src/Microsoft/IO/ThrowHelper.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.IO;
-
-namespace Microsoft.IO
-{
- internal static class ThrowHelper
- {
- internal static void ThrowEndOfFileException()
- {
- throw new EndOfStreamException(SR.IO_EOF_ReadBeyondEOF);
- }
- }
-}
diff --git a/src/libraries/Microsoft.IO.Redist/src/Resources/Strings.resx b/src/libraries/Microsoft.IO.Redist/src/Resources/Strings.resx
deleted file mode 100644
index 66a414fe02e6d..0000000000000
--- a/src/libraries/Microsoft.IO.Redist/src/Resources/Strings.resx
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- The target file '{0}' is a directory, not a file.
-
-
- Invalid File or Directory attributes value.
-
-
- Second path fragment must not be a drive or UNC name.
-
-
- Path must not be a drive.
-
-
- File name cannot be null.
-
-
- Path cannot be null.
-
-
- Enum value was out of legal range.
-
-
- Empty file name is not legal.
-
-
- Empty path name is not legal.
-
-
- Illegal characters in path '{0}'.
-
-
- Invalid seek origin.
-
-
- The directory specified, '{0}', is not a subdirectory of '{1}'.
-
-
- Path cannot be the empty string or all whitespace.
-
-
- Cannot create '{0}' because a file or directory with the same name already exists.
-
-
- The specified directory '{0}' cannot be created.
-
-
- Unable to read beyond the end of the stream.
-
-
- The file '{0}' already exists.
-
-
- Unable to find the specified file.
-
-
- Could not find file '{0}'.
-
-
- The file is too long. This operation is currently limited to supporting files less than 2 gigabytes in size.
-
-
- The link's file system entry type is inconsistent with that of its target: {0}
-
-
- Could not find a part of the path.
-
-
- Could not find a part of the path '{0}'.
-
-
- The specified file name or path is too long, or a component of the specified path is too long.
-
-
- The process cannot access the file '{0}' because it is being used by another process.
-
-
- The process cannot access the file because it is being used by another process.
-
-
- Source and destination path must be different.
-
-
- Source and destination path must have identical roots. Move will not work across volumes.
-
-
- [Unknown]
-
-
- Access to the path is denied.
-
-
- Access to the path '{0}' is denied.
-
-
- File encryption is not supported on this platform.
-
-
- The path '{0}' is too long, or a component of the specified path is too long.
-
-
- Basepath argument is not fully qualified.
-
-
- The path is empty.
-
-
- Drive name must be a root directory (i.e. 'C:\') or a drive letter ('C').
-
-
- Non-negative number required.
-
-
diff --git a/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj b/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj
index b846ab63ea730..1351a67f30f3e 100644
--- a/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj
+++ b/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj
@@ -48,9 +48,8 @@
-
-
-
+
+
diff --git a/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj b/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
index a2a273ed6e042..4148acef7d780 100644
--- a/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
+++ b/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
@@ -6,6 +6,7 @@
+
diff --git a/src/libraries/Native/Unix/System.Native/pal_io.c b/src/libraries/Native/Unix/System.Native/pal_io.c
index 9d313dd6e9951..49aaeca6c2078 100644
--- a/src/libraries/Native/Unix/System.Native/pal_io.c
+++ b/src/libraries/Native/Unix/System.Native/pal_io.c
@@ -1015,7 +1015,7 @@ int32_t SystemNative_FAllocate(intptr_t fd, int64_t offset, int64_t length)
int fileDescriptor = ToFileDescriptor(fd);
int32_t result;
#if HAVE_FALLOCATE // Linux
- while ((result = fallocate(fileDescriptor, FALLOC_FL_KEEP_SIZE, (off_t)offset, (off_t)length)) == EINTR);
+ while ((result = fallocate(fileDescriptor, FALLOC_FL_KEEP_SIZE, (off_t)offset, (off_t)length)) == -1 && errno == EINTR);
#elif defined(F_PREALLOCATE) // macOS
fstore_t fstore;
fstore.fst_flags = F_ALLOCATEALL; // Allocate all requested space or no space at all.
diff --git a/src/libraries/Native/Unix/System.Native/pal_process.c b/src/libraries/Native/Unix/System.Native/pal_process.c
index 5e97d958f74d1..fabdfae76187c 100644
--- a/src/libraries/Native/Unix/System.Native/pal_process.c
+++ b/src/libraries/Native/Unix/System.Native/pal_process.c
@@ -191,6 +191,24 @@ static int SetGroups(uint32_t* userGroups, int32_t userGroupsLength, uint32_t* p
return rv;
}
+typedef void (*VoidIntFn)(int);
+
+static
+VoidIntFn
+handler_from_sigaction (struct sigaction *sa)
+{
+ if (((unsigned int)sa->sa_flags) & SA_SIGINFO)
+ {
+ // work around -Wcast-function-type
+ void (*tmp)(void) = (void (*)(void))sa->sa_sigaction;
+ return (void (*)(int))tmp;
+ }
+ else
+ {
+ return sa->sa_handler;
+ }
+}
+
int32_t SystemNative_ForkAndExecProcess(const char* filename,
char* const argv[],
char* const envp[],
@@ -371,7 +389,7 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename,
}
if (!sigaction(sig, NULL, &sa_old))
{
- void (*oldhandler)(int) = (((unsigned int)sa_old.sa_flags) & SA_SIGINFO) ? (void (*)(int))sa_old.sa_sigaction : sa_old.sa_handler;
+ void (*oldhandler)(int) = handler_from_sigaction (&sa_old);
if (oldhandler != SIG_IGN && oldhandler != SIG_DFL)
{
// It has a custom handler, put the default handler back.
diff --git a/src/libraries/Native/Unix/System.Native/pal_random.js b/src/libraries/Native/Unix/System.Native/pal_random.js
index 8e7c7af05f131..c0bbc9c9f0f9e 100644
--- a/src/libraries/Native/Unix/System.Native/pal_random.js
+++ b/src/libraries/Native/Unix/System.Native/pal_random.js
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-var DotNetEntropyLib = {
+const DotNetEntropyLib = {
$DOTNETENTROPY: {
// batchedQuotaMax is the max number of bytes as specified by the api spec.
// If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
@@ -10,13 +10,13 @@ var DotNetEntropyLib = {
getBatchedRandomValues: function (buffer, bufferLength) {
// for modern web browsers
// map the work array to the memory buffer passed with the length
- for (var i = 0; i < bufferLength; i += this.batchedQuotaMax) {
- var view = new Uint8Array(Module.HEAPU8.buffer, buffer + i, Math.min(bufferLength - i, this.batchedQuotaMax));
+ for (let i = 0; i < bufferLength; i += this.batchedQuotaMax) {
+ const view = new Uint8Array(Module.HEAPU8.buffer, buffer + i, Math.min(bufferLength - i, this.batchedQuotaMax));
crypto.getRandomValues(view)
}
}
},
- dotnet_browser_entropy : function (buffer, bufferLength) {
+ dotnet_browser_entropy: function (buffer, bufferLength) {
// check that we have crypto available
if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') {
DOTNETENTROPY.getBatchedRandomValues(buffer, bufferLength)
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.c
index c907f83a524e7..4dd95a119de59 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.c
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.c
@@ -216,14 +216,8 @@ int32_t AndroidCryptoNative_CipherSetKeyAndIV(CipherCtx* ctx, uint8_t* key, uint
return ReinitializeCipher(ctx);
}
-CipherCtx* AndroidCryptoNative_CipherCreate(CipherInfo* type, uint8_t* key, int32_t keySizeInBits, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc)
+CipherCtx* AndroidCryptoNative_CipherCreate(CipherInfo* type, uint8_t* key, int32_t keySizeInBits, uint8_t* iv, int32_t enc)
{
- if (effectiveKeyLength != 0)
- {
- LOG_ERROR("Non-zero effectiveKeyLength is not supported");
- return FAIL;
- }
-
CipherCtx* ctx = AndroidCryptoNative_CipherCreatePartial(type);
// Update the key size if provided
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.h
index fda90fcc6284f..28d2fc52e8225 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.h
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_cipher.h
@@ -25,7 +25,7 @@ typedef struct CipherCtx
} CipherCtx;
PALEXPORT int32_t AndroidCryptoNative_CipherIsSupported(CipherInfo* type);
-PALEXPORT CipherCtx* AndroidCryptoNative_CipherCreate(CipherInfo* type, uint8_t* key, int32_t keySizeInBits, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc);
+PALEXPORT CipherCtx* AndroidCryptoNative_CipherCreate(CipherInfo* type, uint8_t* key, int32_t keySizeInBits, uint8_t* iv, int32_t enc);
PALEXPORT CipherCtx* AndroidCryptoNative_CipherCreatePartial(CipherInfo* type);
PALEXPORT int32_t AndroidCryptoNative_CipherSetTagLength(CipherCtx* ctx, int32_t tagLength);
PALEXPORT int32_t AndroidCryptoNative_CipherSetKeyAndIV(CipherCtx* ctx, uint8_t* key, uint8_t* iv, int32_t enc);
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
index 2e783f49352de..5675f4c0ca7fb 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
@@ -303,6 +303,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
FALLBACK_FUNCTION(EVP_CIPHER_CTX_reset) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_set_key_length) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_set_padding) \
+ RENAMED_FUNCTION(EVP_CIPHER_get_nid, EVP_CIPHER_nid) \
REQUIRED_FUNCTION(EVP_CipherFinal_ex) \
REQUIRED_FUNCTION(EVP_CipherInit_ex) \
REQUIRED_FUNCTION(EVP_CipherUpdate) \
@@ -757,6 +758,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_reset_ptr
#define EVP_CIPHER_CTX_set_key_length EVP_CIPHER_CTX_set_key_length_ptr
#define EVP_CIPHER_CTX_set_padding EVP_CIPHER_CTX_set_padding_ptr
+#define EVP_CIPHER_get_nid EVP_CIPHER_get_nid_ptr
#define EVP_CipherFinal_ex EVP_CipherFinal_ex_ptr
#define EVP_CipherInit_ex EVP_CipherInit_ex_ptr
#define EVP_CipherUpdate EVP_CipherUpdate_ptr
@@ -1120,6 +1122,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define EVP_PKEY_get_base_id EVP_PKEY_base_id
#define EVP_PKEY_get_size EVP_PKEY_size
#define SSL_get1_peer_certificate SSL_get_peer_certificate
+#define EVP_CIPHER_get_nid EVP_CIPHER_nid
#endif
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h
index dba69f1382d2f..f7de24624eb98 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h
@@ -19,6 +19,7 @@ void ERR_new(void);
void ERR_set_debug(const char *file, int line, const char *func);
void ERR_set_error(int lib, int reason, const char *fmt, ...);
int EVP_CIPHER_CTX_get_original_iv(EVP_CIPHER_CTX *ctx, void *buf, size_t len);
+int EVP_CIPHER_get_nid(const EVP_CIPHER *e);
int EVP_MD_get_size(const EVP_MD* md);
int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits);
int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md);
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c
index 40cfde7fea6f6..351a2cd1ca8cc 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c
@@ -9,7 +9,7 @@
#define KEEP_CURRENT_DIRECTION -1
EVP_CIPHER_CTX*
-CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, unsigned char* iv, int32_t enc)
+CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyLength, unsigned char* iv, int32_t enc)
{
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
@@ -43,15 +43,22 @@ CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyL
}
}
- if (effectiveKeyLength > 0)
+ int nid = EVP_CIPHER_get_nid(type);
+
+ switch (nid)
{
- // Necessary for RC2
- ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, effectiveKeyLength, NULL);
- if (ret <= 0)
- {
- EVP_CIPHER_CTX_free(ctx);
- return NULL;
- }
+ case NID_rc2_ecb:
+ case NID_rc2_cbc:
+ // Necessary for RC2
+ ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, keyLength, NULL);
+ if (ret <= 0)
+ {
+ EVP_CIPHER_CTX_free(ctx);
+ return NULL;
+ }
+ break;
+ default:
+ break;
}
// Perform final initialization specifying the remaining arguments
diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.h
index c0d652a5e67b6..e9586fa93e958 100644
--- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.h
+++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.h
@@ -6,7 +6,7 @@
#include "opensslshim.h"
PALEXPORT EVP_CIPHER_CTX*
-CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, unsigned char* iv, int32_t enc);
+CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyLength, unsigned char* iv, int32_t enc);
PALEXPORT EVP_CIPHER_CTX*
CryptoNative_EvpCipherCreatePartial(const EVP_CIPHER* type);
diff --git a/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CSharpCodeGeneratorTests.cs b/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CSharpCodeGeneratorTests.cs
index 8b9f94b0dbc7b..0256638f5f6a8 100644
--- a/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CSharpCodeGeneratorTests.cs
+++ b/src/libraries/System.CodeDom/tests/System/CodeDom/Compiler/CSharpCodeGeneratorTests.cs
@@ -9,7 +9,6 @@
namespace System.CodeDom.Compiler.Tests
{
- [ActiveIssue("https://github.com/dotnet/runtime/issues/57363", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))]
public class CSharpCodeGeneratorTests
{
private static IEnumerable Identifier_TestData()
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
index 4b5b4b732fdeb..6829f94dec62e 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
@@ -1681,41 +1681,27 @@ public Node DeepClone(int count)
#if DEBUG
Debug.Assert(count == GetCount());
#endif
-
- // Breadth-first traversal to recreate nodes, preorder traversal to replicate nodes.
-
- var originalNodes = new Stack(2 * Log2(count) + 2);
- var newNodes = new Stack(2 * Log2(count) + 2);
Node newRoot = ShallowClone();
- Node? originalCurrent = this;
- Node newCurrent = newRoot;
+ var pendingNodes = new Stack<(Node source, Node target)>(2 * Log2(count) + 2);
+ pendingNodes.Push((this, newRoot));
- while (originalCurrent != null)
+ while (pendingNodes.TryPop(out var next))
{
- originalNodes.Push(originalCurrent);
- newNodes.Push(newCurrent);
- newCurrent.Left = originalCurrent.Left?.ShallowClone();
- originalCurrent = originalCurrent.Left;
- newCurrent = newCurrent.Left!;
- }
+ Node clonedNode;
- while (originalNodes.Count != 0)
- {
- originalCurrent = originalNodes.Pop();
- newCurrent = newNodes.Pop();
-
- Node? originalRight = originalCurrent.Right;
- Node? newRight = originalRight?.ShallowClone();
- newCurrent.Right = newRight;
+ if (next.source.Left is Node left)
+ {
+ clonedNode = left.ShallowClone();
+ next.target.Left = clonedNode;
+ pendingNodes.Push((left, clonedNode));
+ }
- while (originalRight != null)
+ if (next.source.Right is Node right)
{
- originalNodes.Push(originalRight);
- newNodes.Push(newRight!);
- newRight!.Left = originalRight.Left?.ShallowClone();
- originalRight = originalRight.Left;
- newRight = newRight.Left;
+ clonedNode = right.ShallowClone();
+ next.target.Right = clonedNode;
+ pendingNodes.Push((right, clonedNode));
}
}
diff --git a/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs b/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs
index c643df16ef087..cfbd15a6d5394 100644
--- a/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs
+++ b/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.EnsureCapacity.cs
@@ -1,6 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Xunit;
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
index 6d0517bc195e9..9923589b24627 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
@@ -374,11 +374,11 @@ private void ParseSpecs(string? metricsSpecs)
{
if (!MetricSpec.TryParse(specString, out MetricSpec spec))
{
- Log.Message("Failed to parse metric spec: {specString}");
+ Log.Message($"Failed to parse metric spec: {specString}");
}
else
{
- Log.Message("Parsed metric: {spec}");
+ Log.Message($"Parsed metric: {spec}");
if (spec.InstrumentName != null)
{
_aggregationManager!.Include(spec.MeterName, spec.InstrumentName);
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterCategory.cs b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterCategory.cs
index db9a8e52f4242..8fd6b54519b7d 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterCategory.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterCategory.cs
@@ -190,7 +190,7 @@ public static bool CounterExists(string counterName, string categoryName, string
}
///
- /// Registers one extensible performance category of type NumberOfItems32 with the system
+ /// Registers one extensible performance category with counter type NumberOfItems32 with the system
///
[Obsolete("This overload of PerformanceCounterCategory.Create has been deprecated. Use System.Diagnostics.PerformanceCounterCategory.Create(string categoryName, string categoryHelp, PerformanceCounterCategoryType categoryType, string counterName, string counterHelp) instead.")]
public static PerformanceCounterCategory Create(string categoryName, string categoryHelp, string counterName, string counterHelp)
@@ -199,6 +199,9 @@ public static PerformanceCounterCategory Create(string categoryName, string cate
return Create(categoryName, categoryHelp, PerformanceCounterCategoryType.Unknown, new CounterCreationDataCollection(new CounterCreationData[] { customData }));
}
+ ///
+ /// Registers one extensible performance category of the specified category type with counter type NumberOfItems32 with the system
+ ///
public static PerformanceCounterCategory Create(string categoryName, string categoryHelp, PerformanceCounterCategoryType categoryType, string counterName, string counterHelp)
{
CounterCreationData customData = new CounterCreationData(counterName, counterHelp, PerformanceCounterType.NumberOfItems32);
@@ -206,7 +209,7 @@ public static PerformanceCounterCategory Create(string categoryName, string cate
}
///
- /// Registers the extensible performance category with the system on the local machine
+ /// Registers the extensible performance category with the system on the local machine
///
[Obsolete("This overload of PerformanceCounterCategory.Create has been deprecated. Use System.Diagnostics.PerformanceCounterCategory.Create(string categoryName, string categoryHelp, PerformanceCounterCategoryType categoryType, CounterCreationDataCollection counterData) instead.")]
public static PerformanceCounterCategory Create(string categoryName, string categoryHelp, CounterCreationDataCollection counterData)
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/CounterSampleCalculatorTests.cs b/src/libraries/System.Diagnostics.PerformanceCounter/tests/CounterSampleCalculatorTests.cs
index 4173d201c8a89..37b34bf373019 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/CounterSampleCalculatorTests.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/CounterSampleCalculatorTests.cs
@@ -13,9 +13,9 @@ public static class CounterSampleCalculatorTests
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void CounterSampleCalculator_ElapsedTime()
{
- var name = nameof(CounterSampleCalculator_ElapsedTime) + "_Counter";
+ string categoryName = nameof(CounterSampleCalculator_ElapsedTime) + "_Category";
- PerformanceCounter counterSample = CreateCounter(name, PerformanceCounterType.ElapsedTime);
+ PerformanceCounter counterSample = CreateCounter(categoryName, PerformanceCounterType.ElapsedTime);
counterSample.RawValue = Stopwatch.GetTimestamp();
DateTime Start = DateTime.Now;
@@ -25,27 +25,26 @@ public static void CounterSampleCalculator_ElapsedTime()
var counterVal = Helpers.RetryOnAllPlatforms(() => counterSample.NextValue());
var dateTimeVal = DateTime.Now.Subtract(Start).TotalSeconds;
- Helpers.DeleteCategory(name);
+ Helpers.DeleteCategory(categoryName);
Assert.True(Math.Abs(dateTimeVal - counterVal) < .3);
}
- public static PerformanceCounter CreateCounter(string name, PerformanceCounterType counterType)
+ public static PerformanceCounter CreateCounter(string categoryName, PerformanceCounterType counterType)
{
- var category = name + "_Category";
- var instance = name + "_Instance";
+ string counterName = categoryName + "_Counter";
CounterCreationDataCollection ccdc = new CounterCreationDataCollection();
CounterCreationData ccd = new CounterCreationData();
ccd.CounterType = counterType;
- ccd.CounterName = name;
+ ccd.CounterName = counterName;
ccdc.Add(ccd);
- Helpers.DeleteCategory(name);
- PerformanceCounterCategory.Create(category, "description", PerformanceCounterCategoryType.SingleInstance, ccdc);
+ Helpers.DeleteCategory(categoryName);
+ PerformanceCounterCategory.Create(categoryName, "description", PerformanceCounterCategoryType.SingleInstance, ccdc);
- Assert.True(Helpers.PerformanceCounterCategoryCreated(category));
+ Helpers.VerifyPerformanceCounterCategoryCreated(categoryName);
- return new PerformanceCounter(category, name, false);
+ return new PerformanceCounter(categoryName, counterName, readOnly:false);
}
}
}
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/Helpers.cs b/src/libraries/System.Diagnostics.PerformanceCounter/tests/Helpers.cs
index 0cf90e9e4682e..d33a5bbbe0974 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/Helpers.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/Helpers.cs
@@ -17,37 +17,53 @@ internal class Helpers
public static bool CanWriteToPerfCounters { get => PlatformDetection.IsNotWindowsNanoServer; }
public static bool CanReadNetPerfCounters { get => File.Exists(Environment.SystemDirectory + Path.DirectorySeparatorChar + "netfxperf.dll"); }
- public static string CreateCategory(string name, PerformanceCounterCategoryType categoryType)
+ public static void CreateCategory(string categoryName, PerformanceCounterCategoryType categoryType)
{
- var category = name + "_Category";
+ string counterName = categoryName.Replace("_Category", "_Counter");
+ CreateCategory(categoryName, counterName, categoryType);
+ }
+
+ public static void CreateCategory(string categoryName, string counterName, PerformanceCounterCategoryType categoryType)
+ {
+ Assert.EndsWith("_Category", categoryName);
+ Assert.EndsWith("_Counter", counterName);
- // If the categry already exists, delete it, then create it.
- DeleteCategory(name);
- PerformanceCounterCategory.Create(category, "description", categoryType, name, "counter description");
+ // If the category already exists, delete it, then create it.
+ DeleteCategory(categoryName);
+ PerformanceCounterCategory.Create(categoryName, "description", categoryType, counterName, "counter description");
- Assert.True(PerformanceCounterCategoryCreated(category));
- return category;
+ VerifyPerformanceCounterCategoryCreated(categoryName);
}
- public static bool PerformanceCounterCategoryCreated(string category)
+ public static void VerifyPerformanceCounterCategoryCreated(string categoryName)
{
+ Assert.EndsWith("_Category", categoryName);
int tries = 0;
- while (!PerformanceCounterCategory.Exists(category) && tries < 10)
+ while (!PerformanceCounterCategory.Exists(categoryName) && tries < 10)
{
System.Threading.Thread.Sleep(100);
tries++;
}
- return PerformanceCounterCategory.Exists(category);
+ Assert.True(PerformanceCounterCategory.Exists(categoryName));
}
- public static void DeleteCategory(string name)
+ public static void DeleteCategory(string categoryName)
{
- var category = name + "_Category";
- if (PerformanceCounterCategory.Exists(category))
+ Assert.EndsWith("_Category", categoryName);
+ if (PerformanceCounterCategory.Exists(categoryName))
+ {
+ PerformanceCounterCategory.Delete(categoryName);
+ }
+
+ int tries = 0;
+ while (PerformanceCounterCategory.Exists(categoryName) && tries < 10)
{
- PerformanceCounterCategory.Delete(category);
+ System.Threading.Thread.Sleep(100);
+ tries++;
}
+
+ Assert.True(!PerformanceCounterCategory.Exists(categoryName));
}
public static T RetryOnAllPlatforms(Func func)
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterCategoryTests.cs b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterCategoryTests.cs
index 1760032fa2535..77b13ae280d75 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterCategoryTests.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterCategoryTests.cs
@@ -80,60 +80,59 @@ public static void PerformanceCounterCategory_GetCounterHelp_Invalid()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounterCategory_CategoryType_MultiInstance()
{
- var name = nameof(PerformanceCounterCategory_CategoryType_MultiInstance) + "_Counter";
+ string categoryName = nameof(PerformanceCounterCategory_CategoryType_MultiInstance) + "_Category";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.MultiInstance);
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.MultiInstance);
- PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(category));
+ PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(categoryName));
Assert.Equal(PerformanceCounterCategoryType.MultiInstance, Helpers.RetryOnAllPlatforms(() => pcc.CategoryType));
- PerformanceCounterCategory.Delete(category);
+ PerformanceCounterCategory.Delete(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounterCategory_CategoryType_SingleInstance()
{
- var name = nameof(PerformanceCounterCategory_CategoryType_SingleInstance) + "_Counter";
+ string categoryName = nameof(PerformanceCounterCategory_CategoryType_SingleInstance) + "_Category";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.SingleInstance);
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.SingleInstance);
- PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(category));
+ PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(categoryName));
Assert.Equal(PerformanceCounterCategoryType.SingleInstance, Helpers.RetryOnAllPlatforms(() => pcc.CategoryType));
- PerformanceCounterCategory.Delete(category);
+ PerformanceCounterCategory.Delete(categoryName);
}
#pragma warning disable 0618 // obsolete warning
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
public static void PerformanceCounterCategory_Create_Obsolete()
{
- var name = nameof(PerformanceCounterCategory_Create_Obsolete) + "_Counter";
- var category = name + "_Category";
+ string categoryName = nameof(PerformanceCounterCategory_Create_Obsolete) + "_Category";
+ string counterName = nameof(PerformanceCounterCategory_Create_Obsolete) + "_Counter";
- Helpers.DeleteCategory(category);
+ Helpers.DeleteCategory(categoryName);
- PerformanceCounterCategory.Create(category, "category help", name, "counter help");
+ PerformanceCounterCategory.Create(categoryName, "category help", counterName, "counter help");
- Assert.True(PerformanceCounterCategory.Exists(category));
- PerformanceCounterCategory.Delete(category);
+ Assert.True(PerformanceCounterCategory.Exists(categoryName));
+ PerformanceCounterCategory.Delete(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
public static void PerformanceCounterCategory_Create_Obsolete_CCD()
{
- var name = nameof(PerformanceCounterCategory_Create_Obsolete_CCD) + "_Counter";
- var category = name + "_Category";
+ string categoryName = nameof(PerformanceCounterCategory_Create_Obsolete) + "_Category";
- CounterCreationData ccd = new CounterCreationData(name, "counter help", PerformanceCounterType.NumberOfItems32);
+ CounterCreationData ccd = new CounterCreationData(categoryName, "counter help", PerformanceCounterType.NumberOfItems32);
CounterCreationDataCollection ccdc = new CounterCreationDataCollection();
ccdc.Add(ccd);
- Helpers.DeleteCategory(category);
+ Helpers.DeleteCategory(categoryName);
- PerformanceCounterCategory.Create(category, "category help", ccdc);
+ PerformanceCounterCategory.Create(categoryName, "category help", ccdc);
- Assert.True(PerformanceCounterCategory.Exists(category));
- PerformanceCounterCategory.Delete(category);
+ Assert.True(PerformanceCounterCategory.Exists(categoryName));
+ PerformanceCounterCategory.Delete(categoryName);
}
#pragma warning restore 0618
@@ -207,12 +206,12 @@ public static void PerformanceCounterCategory_DeleteCategory_Invalid()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
public static void PerformanceCounterCategory_DeleteCategory()
{
- var name = nameof(PerformanceCounterCategory_DeleteCategory) + "_Counter";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.SingleInstance);
+ string categoryName = nameof(PerformanceCounterCategory_DeleteCategory) + "_Category";
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.SingleInstance);
- PerformanceCounterCategory.Delete(category);
+ PerformanceCounterCategory.Delete(categoryName);
- Assert.False(PerformanceCounterCategory.Exists(category));
+ Assert.False(PerformanceCounterCategory.Exists(categoryName));
}
[Fact]
@@ -226,14 +225,14 @@ public static void PerformanceCounterCategory_Exists_Invalid()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounterCategory_GetCounters()
{
- var name = nameof(PerformanceCounterCategory_GetCounters) + "_Counter";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.SingleInstance);
+ string categoryName = nameof(PerformanceCounterCategory_GetCounters) + "_Category";
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.SingleInstance);
- PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(category));
+ PerformanceCounterCategory pcc = Helpers.RetryOnAllPlatforms(() => new PerformanceCounterCategory(categoryName));
PerformanceCounter[] counters = pcc.GetCounters();
Assert.True(counters.Length > 0);
- PerformanceCounterCategory.Delete(category);
+ PerformanceCounterCategory.Delete(categoryName);
}
[Fact]
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterTests.cs b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterTests.cs
index bfaf5fba64b3d..f54bde425313f 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterTests.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceCounterTests.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Specialized;
+using System.Threading;
using Xunit;
namespace System.Diagnostics.Tests
@@ -26,14 +27,15 @@ public static void PerformanceCounter_CreateCounter_EmptyCounter()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
public static void PerformanceCounter_CreateCounter_Count0()
{
- var name = nameof(PerformanceCounter_CreateCounter_Count0) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, false, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_CreateCounter_Count0) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:false, PerformanceCounterCategoryType.SingleInstance))
{
counterSample.RawValue = 0;
Assert.Equal(0, counterSample.RawValue);
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[Fact]
@@ -50,37 +52,40 @@ public static void PerformanceCounter_CreateCounter_ProcessorCounter()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_CreateCounter_MultiInstanceReadOnly()
{
- var name = nameof(PerformanceCounter_CreateCounter_MultiInstanceReadOnly) + "_Counter";
- var instance = name + "_Instance";
+ string categoryName = nameof(PerformanceCounter_CreateCounter_MultiInstanceReadOnly) + "_Category";
+ string counterName = nameof(PerformanceCounter_CreateCounter_MultiInstanceReadOnly) + "_Counter";
+ string instanceName = nameof(PerformanceCounter_CreateCounter_MultiInstanceReadOnly) + "_Instance";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.MultiInstance);
+ Helpers.CreateCategory(categoryName, counterName, PerformanceCounterCategoryType.MultiInstance);
- using (PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(category, name, instance)))
+ using (PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(categoryName, counterName, instanceName)))
{
- Assert.Equal(name, counterSample.CounterName);
- Assert.Equal(category, counterSample.CategoryName);
- Assert.Equal(instance, counterSample.InstanceName);
+ Assert.Equal(counterName, counterSample.CounterName);
+ Assert.Equal(categoryName, counterSample.CategoryName);
+ Assert.Equal(instanceName, counterSample.InstanceName);
Assert.Equal("counter description", Helpers.RetryOnAllPlatforms(() => counterSample.CounterHelp));
Assert.True(counterSample.ReadOnly);
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_CreateCounter_SetReadOnly()
{
- var name = nameof(PerformanceCounter_CreateCounter_SetReadOnly) + "_Counter";
+ string categoryName = nameof(PerformanceCounter_CreateCounter_SetReadOnly) + "_Category";
+ string counterName = nameof(PerformanceCounter_CreateCounter_SetReadOnly) + "_Counter";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.SingleInstance);
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.SingleInstance);
- using (PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(category, name)))
+ using (PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(categoryName, counterName)))
{
counterSample.ReadOnly = false;
Assert.False(counterSample.ReadOnly);
}
- Helpers.DeleteCategory(name);
+ Helpers.DeleteCategory(categoryName);
}
[Fact]
@@ -106,11 +111,11 @@ public static void PerformanceCounter_SetRawValue_ReadOnly()
[Fact]
public static void PerformanceCounter_GetRawValue_EmptyCategoryName()
{
- var name = nameof(PerformanceCounter_GetRawValue_EmptyCategoryName) + "_Counter";
+ string counterName = nameof(PerformanceCounter_GetRawValue_EmptyCategoryName) + "_Counter";
using (PerformanceCounter counterSample = new PerformanceCounter())
{
counterSample.ReadOnly = false;
- counterSample.CounterName = name;
+ counterSample.CounterName = counterName;
Assert.Throws(() => counterSample.RawValue);
}
@@ -119,11 +124,11 @@ public static void PerformanceCounter_GetRawValue_EmptyCategoryName()
[Fact]
public static void PerformanceCounter_GetRawValue_EmptyCounterName()
{
- var name = nameof(PerformanceCounter_GetRawValue_EmptyCounterName) + "_Counter";
+ string categoryName = nameof(PerformanceCounter_GetRawValue_EmptyCounterName) + "_Category";
using (PerformanceCounter counterSample = new PerformanceCounter())
{
counterSample.ReadOnly = false;
- counterSample.CategoryName = name + "_Category";
+ counterSample.CategoryName = categoryName;
Assert.Throws(() => counterSample.RawValue);
}
@@ -132,27 +137,40 @@ public static void PerformanceCounter_GetRawValue_EmptyCounterName()
[Fact]
public static void PerformanceCounter_GetRawValue_CounterDoesNotExist()
{
- var name = nameof(PerformanceCounter_GetRawValue_CounterDoesNotExist) + "_Counter";
+ string categoryName = nameof(PerformanceCounter_GetRawValue_CounterDoesNotExist) + "_Category";
+ string counterName = nameof(PerformanceCounter_GetRawValue_CounterDoesNotExist) + "_Counter";
+
using (PerformanceCounter counterSample = new PerformanceCounter())
{
counterSample.ReadOnly = false;
- counterSample.CounterName = name;
- counterSample.CategoryName = name + "_Category";
+ counterSample.CounterName = counterName;
+ counterSample.CategoryName = categoryName;
Assert.Throws(() => counterSample.RawValue);
}
}
- [ActiveIssue("https://github.com/dotnet/runtime/issues/29753")]
[Fact]
public static void PerformanceCounter_NextValue_ProcessorCounter()
{
- using (PerformanceCounter counterSample = new PerformanceCounter("Processor", "Interrupts/sec", "0", "."))
+ using (PerformanceCounter counterSample = new PerformanceCounter("Processor", "Interrupts/sec", "_Total", "."))
{
- Helpers.RetryOnAllPlatforms(() => counterSample.NextValue());
- System.Threading.Thread.Sleep(30);
-
- Assert.True(Helpers.RetryOnAllPlatforms(() => counterSample.NextValue()) > 0);
+ float val;
+ int counter = 0;
+ do
+ {
+ // Ensure we don't always return zero for a counter we know is not always zero
+ val = Helpers.RetryOnAllPlatforms(() => counterSample.NextValue());
+ if (val > 0f)
+ {
+ break;
+ }
+ counter++;
+ Thread.Sleep(100);
+ }
+ while (counter < 20);
+
+ Assert.True(val > 0f);
}
}
@@ -182,116 +200,127 @@ public static void PerformanceCounter_BeginInitEndInit_ProcessorCounter()
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_Decrement()
{
- var name = nameof(PerformanceCounter_Decrement) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, false, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_Decrement) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:false, PerformanceCounterCategoryType.SingleInstance))
{
counterSample.RawValue = 10;
Helpers.RetryOnAllPlatforms(() => counterSample.Decrement());
Assert.Equal(9, counterSample.RawValue);
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_Increment()
{
- var name = nameof(PerformanceCounter_Increment) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, false, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_Increment) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:false, PerformanceCounterCategoryType.SingleInstance))
{
counterSample.RawValue = 10;
Helpers.RetryOnAllPlatforms(() => counterSample.Increment());
Assert.Equal(11, Helpers.RetryOnAllPlatforms(() => counterSample.NextSample().RawValue));
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_IncrementBy_IncrementBy2()
{
- var name = nameof(PerformanceCounter_IncrementBy_IncrementBy2) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, false, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_IncrementBy_IncrementBy2) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:false, PerformanceCounterCategoryType.SingleInstance))
{
counterSample.RawValue = 10;
Helpers.RetryOnAllPlatforms(() => counterSample.IncrementBy(2));
- Assert.Equal(12, counterSample.RawValue);
- Helpers.DeleteCategory(name);
+ Assert.Equal(12, Helpers.RetryOnAllPlatforms(() => counterSample.NextSample().RawValue));
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_IncrementBy_IncrementByReadOnly()
{
- var name = nameof(PerformanceCounter_IncrementBy_IncrementByReadOnly) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, true, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_IncrementBy_IncrementByReadOnly) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:true, PerformanceCounterCategoryType.SingleInstance))
{
Assert.Throws(() => counterSample.IncrementBy(2));
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_Increment_IncrementReadOnly()
{
- var name = nameof(PerformanceCounter_Increment_IncrementReadOnly) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, true, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_Increment_IncrementReadOnly) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:true, PerformanceCounterCategoryType.SingleInstance))
{
Assert.Throws(() => counterSample.Increment());
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_Decrement_DecrementReadOnly()
{
- var name = nameof(PerformanceCounter_Decrement_DecrementReadOnly) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, true, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_Decrement_DecrementReadOnly) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:true, PerformanceCounterCategoryType.SingleInstance))
{
Assert.Throws(() => counterSample.Decrement());
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteToPerfCounters))]
public static void PerformanceCounter_RemoveInstance()
{
- var name = nameof(PerformanceCounter_RemoveInstance) + "_Counter";
- using (PerformanceCounter counterSample = CreateCounterWithCategory(name, false, PerformanceCounterCategoryType.SingleInstance))
+ string categoryName = nameof(PerformanceCounter_RemoveInstance) + "_Category";
+ using (PerformanceCounter counterSample = CreateCounterWithCategory(categoryName, readOnly:false, PerformanceCounterCategoryType.SingleInstance))
{
counterSample.RawValue = 100;
counterSample.RemoveInstance();
counterSample.Close();
Assert.NotNull(counterSample);
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
[ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters))]
public static void PerformanceCounter_NextSample_MultiInstance()
{
- var name = nameof(PerformanceCounter_NextSample_MultiInstance) + "_Counter";
- var instance = name + "_Instance";
+ string categoryName = nameof(PerformanceCounter_NextSample_MultiInstance) + "_Category";
+ string counterName = nameof(PerformanceCounter_NextSample_MultiInstance) + "_Counter";
+ string instanceName = nameof(PerformanceCounter_NextSample_MultiInstance) + "_Instance";
- var category = Helpers.CreateCategory(name, PerformanceCounterCategoryType.MultiInstance);
+ Helpers.CreateCategory(categoryName, PerformanceCounterCategoryType.MultiInstance);
- using (PerformanceCounter counterSample = new PerformanceCounter(category, name, instance, false))
+ using (PerformanceCounter counterSample = new PerformanceCounter(categoryName, counterName, instanceName, readOnly:false))
{
counterSample.RawValue = 10;
Helpers.RetryOnAllPlatforms(() => counterSample.Decrement());
Assert.Equal(9, counterSample.RawValue);
- Helpers.DeleteCategory(name);
}
+
+ Helpers.DeleteCategory(categoryName);
}
- public static PerformanceCounter CreateCounterWithCategory(string name, bool readOnly, PerformanceCounterCategoryType categoryType )
+ public static PerformanceCounter CreateCounterWithCategory(string categoryName, bool readOnly, PerformanceCounterCategoryType categoryType)
{
- var category = Helpers.CreateCategory(name, categoryType);
+ Helpers.CreateCategory(categoryName, categoryType);
+
+ string counterName = categoryName.Replace("_Category", "_Counter");
- PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(category, name, readOnly));
+ PerformanceCounter counterSample = Helpers.RetryOnAllPlatforms(() => new PerformanceCounter(categoryName, counterName, readOnly));
return counterSample;
}
diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceDataTests.cs b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceDataTests.cs
index d2864ae7bd3e3..a48b07878b4d0 100644
--- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceDataTests.cs
+++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/PerformanceDataTests.cs
@@ -18,7 +18,7 @@ public PerformanceDataTests(PerformanceDataTestsFixture fixture)
}
// We run the test only if the stress mode is enabled and the process is elvated.
- private static bool IsRunnableEnvironnement => Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters && TestEnvironment.IsStressModeEnabled && RemoteExecutor.IsSupported;
+ private static bool IsRunnableEnvironment => Helpers.IsElevatedAndCanWriteAndReadNetPerfCounters && TestEnvironment.IsStressModeEnabled && RemoteExecutor.IsSupported;
///
/// This test was taken from System.Diagnostics.PerformanceData documentation https://msdn.microsoft.com/en-us/library/system.diagnostics.performancedata(v=vs.110).aspx
@@ -26,7 +26,7 @@ public PerformanceDataTests(PerformanceDataTestsFixture fixture)
/// ctrpp.exe -legacy provider.man
/// rc.exe /r /i "c:\Program Files\Microsoft SDKs\Windows\v6.0\Include" provider.rc
///
- [ConditionalFact(nameof(PerformanceDataTests.IsRunnableEnvironnement))]
+ [ConditionalFact(nameof(PerformanceDataTests.IsRunnableEnvironment))]
public void PerformanceCounter_PerformanceData()
{
// We run test in isolated process to avoid interferences on internal performance counter shared state with other tests.
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj
index 108bf2f43b9f2..8ee73ae4c1d28 100644
--- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj
@@ -67,7 +67,11 @@
+
+
+ Common\System\LocalAppContextSwitches.Common.cs
+
Common\Interop\Linux\OpenLdap\Interop.Ldap.cs
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs
index 701fae2610828..d67782f40ad36 100644
--- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs
@@ -123,7 +123,31 @@ internal static int BindToDirectory(ConnectionHandle ld, string who, string pass
}
}
- internal static int StartTls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls) => Interop.Ldap.ldap_start_tls(ldapHandle, ref ServerReturnValue, ref Message, ServerControls, ClientControls);
+ internal static int StartTls(ConnectionHandle ldapHandle, ref int serverReturnValue, ref IntPtr message, IntPtr serverControls, IntPtr clientControls)
+ {
+ // Windows and Linux have different signatures for ldap_start_tls_s.
+ // On Linux, we don't have a serverReturnValue or the message/result parameter.
+ //
+ // So in the PAL here, just emulate.
+
+ int error = Interop.Ldap.ldap_start_tls(ldapHandle, serverControls, clientControls);
+
+ // On Windows, serverReturnValue only has meaning if the result code is LDAP_OTHER.
+ // If OpenLDAP returns that, we don't have a better code, so assign that through.
+ // If we get any other error, assign serverReturnValue to 0 since it shouldn't be read.
+ if (error == (int)ResultCode.Other)
+ {
+ serverReturnValue = error;
+ }
+ else
+ {
+ serverReturnValue = 0;
+ }
+
+ // We don't have a referrer/message/result value, so just set it to NULL.
+ message = IntPtr.Zero;
+ return error;
+ }
// openldap doesn't have a ldap_stop_tls function. Returning true as no-op for Linux.
internal static byte StopTls(ConnectionHandle ldapHandle) => 1;
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs
index 2383e816e1ddb..a7e43947e2031 100644
--- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs
@@ -16,6 +16,13 @@ public ConnectionHandle()
_needDispose = true;
}
+ internal ConnectionHandle(string uri)
+ :base(true)
+ {
+ Interop.Ldap.ldap_initialize(out handle, uri);
+ _needDispose = true;
+ }
+
internal ConnectionHandle(IntPtr value, bool disposeHandle) : base(true)
{
_needDispose = disposeHandle;
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs
index 02c8f0c239587..6adf1ebac982c 100644
--- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs
@@ -20,7 +20,7 @@ private void InternalInitConnectionHandle(string hostname)
throw new NullReferenceException();
}
- _ldapHandle = new ConnectionHandle();
+ _ldapHandle = new ConnectionHandle($"ldap://{hostname}:{((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber}");
}
private int InternalConnectToServer()
@@ -79,13 +79,39 @@ private int InternalConnectToServer()
private int InternalBind(NetworkCredential tempCredential, SEC_WINNT_AUTH_IDENTITY_EX cred, BindMethod method)
{
int error;
- if (tempCredential == null && (AuthType == AuthType.External || AuthType == AuthType.Kerberos))
+
+ if (LocalAppContextSwitches.UseBasicAuthFallback)
{
- error = BindSasl();
+ if (tempCredential == null && (AuthType == AuthType.External || AuthType == AuthType.Kerberos))
+ {
+ error = BindSasl();
+ }
+ else
+ {
+ error = LdapPal.BindToDirectory(_ldapHandle, cred.user, cred.password);
+ }
}
else
{
- error = LdapPal.BindToDirectory(_ldapHandle, cred.user, cred.password);
+ if (method == BindMethod.LDAP_AUTH_NEGOTIATE)
+ {
+ if (tempCredential == null)
+ {
+ error = BindSasl();
+ }
+ else
+ {
+ // Explicit credentials were provided. If we call ldap_bind_s it will
+ // return LDAP_NOT_SUPPORTED, so just skip the P/Invoke.
+ error = (int)LdapError.NotSupported;
+ }
+ }
+ else
+ {
+ // Basic and Anonymous are handled elsewhere.
+ Debug.Assert(AuthType != AuthType.Anonymous && AuthType != AuthType.Basic);
+ error = (int)LdapError.AuthUnknown;
+ }
}
return error;
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs
index 5b28020eed2fd..9a200fc5ba218 100644
--- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs
@@ -641,11 +641,14 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro
response.ResponseName = "1.3.6.1.4.1.1466.20037";
throw new TlsOperationException(response);
}
- else if (LdapErrorMappings.IsLdapError(error))
+
+ if (LdapErrorMappings.IsLdapError(error))
{
string errorMessage = LdapErrorMappings.MapResultCode(error);
throw new LdapException(error, errorMessage);
}
+
+ throw new LdapException(error);
}
}
finally
diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs
new file mode 100644
index 0000000000000..59ddfdf7f10ed
--- /dev/null
+++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LocalAppContextSwitches.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ internal static partial class LocalAppContextSwitches
+ {
+ private static int s_useBasicAuthFallback;
+
+ public static bool UseBasicAuthFallback
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => GetCachedSwitchValue("System.DirectoryServices.Protocols.UseBasicAuthFallback", ref s_useBasicAuthFallback);
+ }
+ }
+}
diff --git a/src/libraries/System.Drawing.Common/tests/FontTests.cs b/src/libraries/System.Drawing.Common/tests/FontTests.cs
index de260a5914083..899bd4e3c1040 100644
--- a/src/libraries/System.Drawing.Common/tests/FontTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/FontTests.cs
@@ -800,7 +800,7 @@ public void ToLogFont_Invoke_ReturnsExpected(FontStyle fontStyle, byte gdiCharSe
Assert.Equal(font.Italic ? 1 : 0, logFont.lfItalic);
Assert.Equal(font.Underline ? 1 : 0, logFont.lfUnderline);
Assert.Equal(font.Strikeout ? 1 : 0, logFont.lfStrikeOut);
- Assert.Equal(font.GdiCharSet, logFont.lfCharSet);
+ Assert.Equal(SystemFonts.DefaultFont.GdiCharSet <= 2 ? font.GdiCharSet : SystemFonts.DefaultFont.GdiCharSet, logFont.lfCharSet);
Assert.Equal(0, logFont.lfOutPrecision);
Assert.Equal(0, logFont.lfClipPrecision);
Assert.Equal(0, logFont.lfQuality);
@@ -837,7 +837,7 @@ public void ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRende
Assert.Equal(0, logFont.lfItalic);
Assert.Equal(0, logFont.lfUnderline);
Assert.Equal(0, logFont.lfStrikeOut);
- Assert.Equal(1, logFont.lfCharSet);
+ Assert.Equal(SystemFonts.DefaultFont.GdiCharSet <= 2 ? font.GdiCharSet : SystemFonts.DefaultFont.GdiCharSet, logFont.lfCharSet);
Assert.Equal(0, logFont.lfOutPrecision);
Assert.Equal(0, logFont.lfClipPrecision);
Assert.Equal(0, logFont.lfQuality);
diff --git a/src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln b/src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln
index 1958430a9e5ab..c4e10f55f1aa7 100644
--- a/src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln
+++ b/src/libraries/System.IO.FileSystem/System.IO.FileSystem.sln
@@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Disabl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Manual.Tests", "tests\ManualTests\System.IO.FileSystem.Manual.Tests.csproj", "{534152EB-14A8-4EF4-B181-342A555337F1}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Net5Compat.Tests", "tests\Net5CompatTests\System.IO.FileSystem.Net5Compat.Tests.csproj", "{48E07F12-8597-40DE-8A37-CCBEB9D54012}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem.Tests", "tests\System.IO.FileSystem.Tests.csproj", "{3A8E16D3-8A22-4076-BB48-2CD1FBFAF81B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{79A74577-C550-4264-B352-51D304796B89}"
diff --git a/src/libraries/System.IO.FileSystem/tests/File/Append.cs b/src/libraries/System.IO.FileSystem/tests/File/Append.cs
index 8cb28b7ca38ac..68160715a7d63 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/Append.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/Append.cs
@@ -8,6 +8,8 @@ namespace System.IO.Tests
{
public class File_AppendText : File_ReadWriteAllText
{
+ protected override bool IsAppend => true;
+
protected override void Write(string path, string content)
{
var writer = File.AppendText(path);
@@ -15,34 +17,26 @@ protected override void Write(string path, string content)
writer.Dispose();
}
- [Fact]
- public override void Overwrite()
+ protected override void Write(string path, string content, Encoding encoding)
{
- string path = GetTestFilePath();
- string lines = new string('c', 200);
- string appendLines = new string('b', 100);
- Write(path, lines);
- Write(path, appendLines);
- Assert.Equal(lines + appendLines, Read(path));
+ var writer = new StreamWriter(path, IsAppend, encoding);
+ writer.Write(content);
+ writer.Dispose();
}
}
public class File_AppendAllText : File_ReadWriteAllText
{
+ protected override bool IsAppend => true;
+
protected override void Write(string path, string content)
{
File.AppendAllText(path, content);
}
- [Fact]
- public override void Overwrite()
+ protected override void Write(string path, string content, Encoding encoding)
{
- string path = GetTestFilePath();
- string lines = new string('c', 200);
- string appendLines = new string('b', 100);
- Write(path, lines);
- Write(path, appendLines);
- Assert.Equal(lines + appendLines, Read(path));
+ File.AppendAllText(path, content, encoding);
}
}
@@ -62,21 +56,12 @@ public void NullEncoding()
public class File_AppendAllLines : File_ReadWriteAllLines_Enumerable
{
+ protected override bool IsAppend => true;
+
protected override void Write(string path, string[] content)
{
File.AppendAllLines(path, content);
}
-
- [Fact]
- public override void Overwrite()
- {
- string path = GetTestFilePath();
- string[] lines = new string[] { new string('c', 200) };
- string[] appendLines = new string[] { new string('b', 100) };
- Write(path, lines);
- Write(path, appendLines);
- Assert.Equal(new string[] { lines[0], appendLines[0] }, Read(path));
- }
}
public class File_AppendAllLines_Encoded : File_AppendAllLines
diff --git a/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs
index 457366266d69c..dbe1d5197fcdf 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/AppendAsync.cs
@@ -10,18 +10,11 @@ namespace System.IO.Tests
{
public class File_AppendAllTextAsync : File_ReadWriteAllTextAsync
{
+ protected override bool IsAppend => true;
+
protected override Task WriteAsync(string path, string content) => File.AppendAllTextAsync(path, content);
- [Fact]
- public override async Task OverwriteAsync()
- {
- string path = GetTestFilePath();
- string lines = new string('c', 200);
- string appendLines = new string('b', 100);
- await WriteAsync(path, lines);
- await WriteAsync(path, appendLines);
- Assert.Equal(lines + appendLines, await ReadAsync(path));
- }
+ protected override Task WriteAsync(string path, string content, Encoding encoding) => File.AppendAllTextAsync(path, content, encoding);
[Fact]
public override Task TaskAlreadyCanceledAsync()
@@ -60,18 +53,9 @@ public override Task TaskAlreadyCanceledAsync()
public class File_AppendAllLinesAsync : File_ReadWriteAllLines_EnumerableAsync
{
- protected override Task WriteAsync(string path, string[] content) => File.AppendAllLinesAsync(path, content);
+ protected override bool IsAppend => true;
- [Fact]
- public override async Task OverwriteAsync()
- {
- string path = GetTestFilePath();
- string[] lines = new string[] { new string('c', 200) };
- string[] appendLines = new string[] { new string('b', 100) };
- await WriteAsync(path, lines);
- await WriteAsync(path, appendLines);
- Assert.Equal(new string[] { lines[0], appendLines[0] }, await ReadAsync(path));
- }
+ protected override Task WriteAsync(string path, string[] content) => File.AppendAllLinesAsync(path, content);
[Fact]
public override Task TaskAlreadyCanceledAsync()
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
index 54c7643766335..679ff9b5b7986 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
@@ -2,8 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using System.IO.Pipes;
+using Microsoft.DotNet.XUnitExtensions;
namespace System.IO.Tests
{
@@ -172,5 +175,62 @@ public void ProcFs_NotEmpty(string path)
{
Assert.InRange(File.ReadAllBytes(path).Length, 1, int.MaxValue);
}
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // DOS device paths (\\.\ and \\?\) are a Windows concept
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60427")]
+ public async Task ReadAllBytes_NonSeekableFileStream_InWindows()
+ {
+ string pipeName = FileSystemTest.GetNamedPipeServerStreamName();
+ string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}");
+
+ var namedPipeWriterStream = new NamedPipeServerStream(pipeName, PipeDirection.Out);
+ var contentBytes = new byte[] { 1, 2, 3 };
+
+ using (var cts = new CancellationTokenSource())
+ {
+ Task writingServerTask = WaitConnectionAndWritePipeStreamAsync(namedPipeWriterStream, contentBytes, cts.Token);
+ Task readTask = Task.Run(() => File.ReadAllBytes(pipePath), cts.Token);
+ cts.CancelAfter(TimeSpan.FromSeconds(3));
+
+ await writingServerTask;
+ byte[] readBytes = await readTask;
+ Assert.Equal(contentBytes, readBytes);
+ }
+
+ static async Task WaitConnectionAndWritePipeStreamAsync(NamedPipeServerStream namedPipeWriterStream, byte[] contentBytes, CancellationToken cancellationToken)
+ {
+ await using (namedPipeWriterStream)
+ {
+ await namedPipeWriterStream.WaitForConnectionAsync(cancellationToken);
+ await namedPipeWriterStream.WriteAsync(contentBytes, cancellationToken);
+ }
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public async Task ReadAllBytes_NonSeekableFileStream_InUnix()
+ {
+ string fifoPath = GetTestFilePath();
+ Assert.Equal(0, mkfifo(fifoPath, 438 /* 666 in octal */ ));
+
+ var contentBytes = new byte[] { 1, 2, 3 };
+
+ await Task.WhenAll(
+ Task.Run(() =>
+ {
+ byte[] readBytes = File.ReadAllBytes(fifoPath);
+ Assert.Equal(contentBytes, readBytes);
+ }),
+ Task.Run(() =>
+ {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Write, FileShare.Read);
+ foreach (byte content in contentBytes)
+ {
+ fs.WriteByte(content);
+ }
+ }));
+ }
}
}
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
index 748c01dbffb8f..be562f15ca953 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
@@ -5,6 +5,8 @@
using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using System.IO.Pipes;
+using Microsoft.DotNet.XUnitExtensions;
namespace System.IO.Tests
{
@@ -186,5 +188,61 @@ public async Task ProcFs_NotEmpty(string path)
{
Assert.InRange((await File.ReadAllBytesAsync(path)).Length, 1, int.MaxValue);
}
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // DOS device paths (\\.\ and \\?\) are a Windows concept
+ public async Task ReadAllBytesAsync_NonSeekableFileStream_InWindows()
+ {
+ string pipeName = FileSystemTest.GetNamedPipeServerStreamName();
+ string pipePath = Path.GetFullPath($@"\\.\pipe\{pipeName}");
+
+ var namedPipeWriterStream = new NamedPipeServerStream(pipeName, PipeDirection.Out);
+ var contentBytes = new byte[] { 1, 2, 3 };
+
+ using (var cts = new CancellationTokenSource())
+ {
+ Task writingServerTask = WaitConnectionAndWritePipeStreamAsync(namedPipeWriterStream, contentBytes, cts.Token);
+ Task readTask = File.ReadAllBytesAsync(pipePath, cts.Token);
+ cts.CancelAfter(TimeSpan.FromSeconds(50));
+
+ await writingServerTask;
+ byte[] readBytes = await readTask;
+ Assert.Equal(contentBytes, readBytes);
+ }
+
+ static async Task WaitConnectionAndWritePipeStreamAsync(NamedPipeServerStream namedPipeWriterStream, byte[] contentBytes, CancellationToken cancellationToken)
+ {
+ await using (namedPipeWriterStream)
+ {
+ await namedPipeWriterStream.WaitForConnectionAsync(cancellationToken);
+ await namedPipeWriterStream.WriteAsync(contentBytes, cancellationToken);
+ }
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public async Task ReadAllBytesAsync_NonSeekableFileStream_InUnix()
+ {
+ string fifoPath = GetTestFilePath();
+ Assert.Equal(0, mkfifo(fifoPath, 438 /* 666 in octal */ ));
+
+ var contentBytes = new byte[] { 1, 2, 3 };
+
+ await Task.WhenAll(
+ Task.Run(async () =>
+ {
+ byte[] readBytes = await File.ReadAllBytesAsync(fifoPath);
+ Assert.Equal(contentBytes, readBytes);
+ }),
+ Task.Run(() =>
+ {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Write, FileShare.Read);
+ foreach (byte content in contentBytes)
+ {
+ fs.WriteByte(content);
+ }
+ }));
+ }
}
}
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLines.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLines.cs
index 99c94b450790f..99de941c39175 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLines.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLines.cs
@@ -12,6 +12,8 @@ public class File_ReadWriteAllLines_Enumerable : FileSystemTest
{
#region Utilities
+ protected virtual bool IsAppend { get; }
+
protected virtual void Write(string path, string[] content)
{
File.WriteAllLines(path, (IEnumerable)content);
@@ -66,15 +68,28 @@ public void ValidWrite(int size)
Assert.Equal(lines, Read(path));
}
- [Fact]
- public virtual void Overwrite()
+ [Theory]
+ [InlineData(200, 100)]
+ [InlineData(50_000, 40_000)] // tests a different code path than the line above
+ public void AppendOrOverwrite(int linesSizeLength, int overwriteLinesLength)
{
string path = GetTestFilePath();
- string[] lines = new string[] { new string('c', 200) };
- string[] overwriteLines = new string[] { new string('b', 100) };
+ string[] lines = new string[] { new string('c', linesSizeLength) };
+ string[] overwriteLines = new string[] { new string('b', overwriteLinesLength) };
+
Write(path, lines);
Write(path, overwriteLines);
- Assert.Equal(overwriteLines, Read(path));
+
+ if (IsAppend)
+ {
+ Assert.Equal(new string[] { lines[0], overwriteLines[0] }, Read(path));
+ }
+ else
+ {
+ Assert.DoesNotContain("Append", GetType().Name); // ensure that all "Append" types override this property
+
+ Assert.Equal(overwriteLines, Read(path));
+ }
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsFileLockingEnabled))]
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLinesAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLinesAsync.cs
index b2a1288639db3..3114e649e6635 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLinesAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllLinesAsync.cs
@@ -15,6 +15,8 @@ public class File_ReadWriteAllLines_EnumerableAsync : FileSystemTest
{
#region Utilities
+ protected virtual bool IsAppend { get; }
+
protected virtual Task WriteAsync(string path, string[] content) =>
File.WriteAllLinesAsync(path, content);
@@ -64,15 +66,29 @@ public async Task ValidWriteAsync(int size)
Assert.Equal(lines, await ReadAsync(path));
}
- [Fact]
- public virtual async Task OverwriteAsync()
+
+ [Theory]
+ [InlineData(200, 100)]
+ [InlineData(50_000, 40_000)] // tests a different code path than the line above
+ public async Task AppendOrOverwrite(int linesSizeLength, int overwriteLinesLength)
{
string path = GetTestFilePath();
- string[] lines = { new string('c', 200) };
- string[] overwriteLines = { new string('b', 100) };
+ string[] lines = new string[] { new string('c', linesSizeLength) };
+ string[] overwriteLines = new string[] { new string('b', overwriteLinesLength) };
+
await WriteAsync(path, lines);
await WriteAsync(path, overwriteLines);
- Assert.Equal(overwriteLines, await ReadAsync(path));
+
+ if (IsAppend)
+ {
+ Assert.Equal(new string[] { lines[0], overwriteLines[0] }, await ReadAsync(path));
+ }
+ else
+ {
+ Assert.DoesNotContain("Append", GetType().Name); // ensure that all "Append" types override this property
+
+ Assert.Equal(overwriteLines, await ReadAsync(path));
+ }
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsFileLockingEnabled))]
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllText.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllText.cs
index 1dbe303849658..8c9c1e66e72a4 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllText.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllText.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
using System.Text;
using Xunit;
@@ -10,11 +11,18 @@ public class File_ReadWriteAllText : FileSystemTest
{
#region Utilities
+ protected virtual bool IsAppend { get; }
+
protected virtual void Write(string path, string content)
{
File.WriteAllText(path, content);
}
+ protected virtual void Write(string path, string content, Encoding encoding)
+ {
+ File.WriteAllText(path, content, encoding);
+ }
+
protected virtual string Read(string path)
{
return File.ReadAllText(path);
@@ -73,15 +81,28 @@ public void ValidWrite(int size)
Assert.Equal(toWrite, Read(path));
}
- [Fact]
- public virtual void Overwrite()
+ [Theory]
+ [InlineData(200, 100)]
+ [InlineData(50_000, 40_000)] // tests a different code path than the line above
+ public void AppendOrOverwrite(int linesSizeLength, int overwriteLinesLength)
{
string path = GetTestFilePath();
- string lines = new string('c', 200);
- string overwriteLines = new string('b', 100);
+ string lines = new string('c', linesSizeLength);
+ string overwriteLines = new string('b', overwriteLinesLength);
+
Write(path, lines);
Write(path, overwriteLines);
- Assert.Equal(overwriteLines, Read(path));
+
+ if (IsAppend)
+ {
+ Assert.Equal(lines + overwriteLines, Read(path));
+ }
+ else
+ {
+ Assert.DoesNotContain("Append", GetType().Name); // ensure that all "Append" types override this property
+
+ Assert.Equal(overwriteLines, Read(path));
+ }
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsFileLockingEnabled))]
@@ -133,6 +154,56 @@ public void WriteToReadOnlyFile()
}
}
+ public static IEnumerable OutputIsTheSameAsForStreamWriter_Args()
+ {
+ string longText = new string('z', 50_000);
+ foreach (Encoding encoding in new[] { Encoding.Unicode , new UTF8Encoding(encoderShouldEmitUTF8Identifier: true), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false) })
+ {
+ foreach (string text in new[] { null, string.Empty, " ", "shortText", longText })
+ {
+ yield return new object[] { text, encoding };
+ }
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(OutputIsTheSameAsForStreamWriter_Args))]
+ public void OutputIsTheSameAsForStreamWriter(string content, Encoding encoding)
+ {
+ string filePath = GetTestFilePath();
+ Write(filePath, content, encoding); // it uses System.IO.File APIs
+
+ string swPath = GetTestFilePath();
+ using (StreamWriter sw = new StreamWriter(swPath, IsAppend, encoding))
+ {
+ sw.Write(content);
+ }
+
+ Assert.Equal(File.ReadAllText(swPath, encoding), File.ReadAllText(filePath, encoding));
+ Assert.Equal(File.ReadAllBytes(swPath), File.ReadAllBytes(filePath)); // ensure Preamble was stored
+ }
+
+ [Theory]
+ [MemberData(nameof(OutputIsTheSameAsForStreamWriter_Args))]
+ public void OutputIsTheSameAsForStreamWriter_Overwrite(string content, Encoding encoding)
+ {
+ string filePath = GetTestFilePath();
+ string swPath = GetTestFilePath();
+
+ for (int i = 0; i < 2; i++)
+ {
+ Write(filePath, content, encoding); // it uses System.IO.File APIs
+
+ using (StreamWriter sw = new StreamWriter(swPath, IsAppend, encoding))
+ {
+ sw.Write(content);
+ }
+ }
+
+ Assert.Equal(File.ReadAllText(swPath, encoding), File.ReadAllText(filePath, encoding));
+ Assert.Equal(File.ReadAllBytes(swPath), File.ReadAllBytes(filePath)); // ensure Preamble was stored once
+ }
+
#endregion
}
diff --git a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllTextAsync.cs b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllTextAsync.cs
index 3ad76c272fff6..4a33f94f7b8f8 100644
--- a/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllTextAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/File/ReadWriteAllTextAsync.cs
@@ -12,10 +12,14 @@ namespace System.IO.Tests
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
public class File_ReadWriteAllTextAsync : FileSystemTest
{
+ protected virtual bool IsAppend { get; }
+
#region Utilities
protected virtual Task WriteAsync(string path, string content) => File.WriteAllTextAsync(path, content);
+ protected virtual Task WriteAsync(string path, string content, Encoding encoding) => File.WriteAllTextAsync(path, content, encoding);
+
protected virtual Task ReadAsync(string path) => File.ReadAllTextAsync(path);
#endregion
@@ -72,15 +76,28 @@ public async Task ValidWriteAsync(int size)
Assert.Equal(toWrite, await ReadAsync(path));
}
- [Fact]
- public virtual async Task OverwriteAsync()
+ [Theory]
+ [InlineData(200, 100)]
+ [InlineData(50_000, 40_000)] // tests a different code path than the line above
+ public async Task AppendOrOverwriteAsync(int linesSizeLength, int overwriteLinesLength)
{
string path = GetTestFilePath();
- string lines = new string('c', 200);
- string overwriteLines = new string('b', 100);
+ string lines = new string('c', linesSizeLength);
+ string overwriteLines = new string('b', overwriteLinesLength);
+
await WriteAsync(path, lines);
- await WriteAsync(path, overwriteLines);
- Assert.Equal(overwriteLines, await ReadAsync(path));
+ await WriteAsync(path, overwriteLines); ;
+
+ if (IsAppend)
+ {
+ Assert.Equal(lines + overwriteLines, await ReadAsync(path));
+ }
+ else
+ {
+ Assert.DoesNotContain("Append", GetType().Name); // ensure that all "Append" types override this property
+
+ Assert.Equal(overwriteLines, await ReadAsync(path));
+ }
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsFileLockingEnabled))]
@@ -141,6 +158,44 @@ public virtual Task TaskAlreadyCanceledAsync()
async () => await File.WriteAllTextAsync(path, "", token));
}
+ [Theory]
+ [MemberData(nameof(File_ReadWriteAllText.OutputIsTheSameAsForStreamWriter_Args), MemberType = typeof(File_ReadWriteAllText))]
+ public async Task OutputIsTheSameAsForStreamWriterAsync(string content, Encoding encoding)
+ {
+ string filePath = GetTestFilePath();
+ await WriteAsync(filePath, content, encoding); // it uses System.File.IO APIs
+
+ string swPath = GetTestFilePath();
+ using (StreamWriter sw = new StreamWriter(swPath, IsAppend, encoding))
+ {
+ await sw.WriteAsync(content);
+ }
+
+ Assert.Equal(await File.ReadAllTextAsync(swPath, encoding), await File.ReadAllTextAsync(filePath, encoding));
+ Assert.Equal(await File.ReadAllBytesAsync(swPath), await File.ReadAllBytesAsync(filePath)); // ensure Preamble was stored
+ }
+
+ [Theory]
+ [MemberData(nameof(File_ReadWriteAllText.OutputIsTheSameAsForStreamWriter_Args), MemberType = typeof(File_ReadWriteAllText))]
+ public async Task OutputIsTheSameAsForStreamWriter_OverwriteAsync(string content, Encoding encoding)
+ {
+ string filePath = GetTestFilePath();
+ string swPath = GetTestFilePath();
+
+ for (int i = 0; i < 2; i++)
+ {
+ await WriteAsync(filePath, content, encoding); // it uses System.File.IO APIs
+
+ using (StreamWriter sw = new StreamWriter(swPath, IsAppend, encoding))
+ {
+ await sw.WriteAsync(content);
+ }
+ }
+
+ Assert.Equal(await File.ReadAllTextAsync(swPath, encoding), await File.ReadAllTextAsync(filePath, encoding));
+ Assert.Equal(await File.ReadAllBytesAsync(swPath), await File.ReadAllBytesAsync(filePath)); // ensure Preamble was stored once
+ }
+
#endregion
}
diff --git a/src/libraries/System.IO.FileSystem/tests/FileInfo/AppendText.cs b/src/libraries/System.IO.FileSystem/tests/FileInfo/AppendText.cs
index eb86294b11974..2a73f63ecf04f 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileInfo/AppendText.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileInfo/AppendText.cs
@@ -1,12 +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.Text;
using Xunit;
namespace System.IO.Tests
{
public class FileInfo_AppendText : File_ReadWriteAllText
{
+ protected override bool IsAppend => true;
+
protected override void Write(string path, string content)
{
var writer = new FileInfo(path).AppendText();
@@ -14,15 +17,11 @@ protected override void Write(string path, string content)
writer.Dispose();
}
- [Fact]
- public override void Overwrite()
+ protected override void Write(string path, string content, Encoding encoding)
{
- string path = GetTestFilePath();
- string lines = new string('c', 200);
- string appendline = new string('b', 100);
- Write(path, lines);
- Write(path, appendline);
- Assert.Equal(lines + appendline, Read(path));
+ var writer = new StreamWriter(path, IsAppend, encoding);
+ writer.Write(content);
+ writer.Dispose();
}
}
}
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/DeleteOnClose.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/DeleteOnClose.cs
index 72150266a2ce0..ea32adc5352ad 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/DeleteOnClose.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/DeleteOnClose.cs
@@ -10,6 +10,7 @@ namespace System.IO.Tests
public class FileStream_DeleteOnClose : FileSystemTest
{
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsFileLockingEnabled), nameof(PlatformDetection.IsThreadingSupported))]
+ [OuterLoop]
public async Task OpenOrCreate_DeleteOnClose_UsableAsMutex()
{
var cts = new CancellationTokenSource();
@@ -69,7 +70,7 @@ public async Task OpenOrCreate_DeleteOnClose_UsableAsMutex()
}
// Wait for 1000 locks.
- cts.CancelAfter(TimeSpan.FromSeconds(60)); // Test timeout.
+ cts.CancelAfter(TimeSpan.FromSeconds(120)); // Test timeout (reason for outerloop)
Volatile.Write(ref locksRemaining, 500);
await Task.WhenAll(tasks);
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs
new file mode 100644
index 0000000000000..ede852c7305b3
--- /dev/null
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/DevicesPipesAndSockets.cs
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.DotNet.XUnitExtensions;
+using Microsoft.Win32.SafeHandles;
+using System.Collections.Generic;
+using System.IO.Pipes;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public class DevicesPipesAndSockets : FileSystemTest
+ {
+ [Theory]
+ [MemberData(nameof(DevicePath_FileOptions_TestData))]
+ public void CharacterDevice_FileStream_Write(string devicePath, FileOptions fileOptions)
+ {
+ FileStreamOptions options = new() { Options = fileOptions, Access = FileAccess.Write, Share = FileShare.Write };
+ using FileStream fs = new(devicePath, options);
+ fs.Write(Encoding.UTF8.GetBytes("foo"));
+ }
+
+ [Theory]
+ [MemberData(nameof(DevicePath_FileOptions_TestData))]
+ public async Task CharacterDevice_FileStream_WriteAsync(string devicePath, FileOptions fileOptions)
+ {
+ FileStreamOptions options = new() { Options = fileOptions, Access = FileAccess.Write, Share = FileShare.Write };
+ using FileStream fs = new(devicePath, options);
+ await fs.WriteAsync(Encoding.UTF8.GetBytes("foo"));
+ }
+
+ [Theory]
+ [MemberData(nameof(DevicePath_TestData))]
+ public void CharacterDevice_WriteAllBytes(string devicePath)
+ {
+ File.WriteAllBytes(devicePath, Encoding.UTF8.GetBytes("foo"));
+ }
+
+ [Theory]
+ [MemberData(nameof(DevicePath_TestData))]
+ public async Task CharacterDevice_WriteAllBytesAsync(string devicePath)
+ {
+ await File.WriteAllBytesAsync(devicePath, Encoding.UTF8.GetBytes("foo"));
+ }
+
+ [Theory]
+ [MemberData(nameof(DevicePath_TestData))]
+ public void CharacterDevice_WriteAllText(string devicePath)
+ {
+ File.WriteAllText(devicePath, "foo");
+ }
+
+ [Theory]
+ [MemberData(nameof(DevicePath_TestData))]
+ public async Task CharacterDevice_WriteAllTextAsync(string devicePath)
+ {
+ await File.WriteAllTextAsync(devicePath, "foo");
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public async Task NamedPipe_ReadWrite()
+ {
+ string fifoPath = GetTestFilePath();
+ Assert.Equal(0, mkfifo(fifoPath, 438 /* 666 in octal */ ));
+
+ await Task.WhenAll(
+ Task.Run(() =>
+ {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ ReadByte(fs, 42);
+ }),
+ Task.Run(() =>
+ {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Write, FileShare.Read);
+ WriteByte(fs, 42);
+ }));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public async Task NamedPipe_ReadWrite_Async()
+ {
+ string fifoPath = GetTestFilePath();
+ Assert.Equal(0, mkfifo(fifoPath, 438 /* 666 in octal */ ));
+
+ await Task.WhenAll(
+ Task.Run(async () => {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ await ReadByteAsync(fs, 42);
+ }),
+ Task.Run(async () =>
+ {
+ using var fs = new FileStream(fifoPath, FileMode.Open, FileAccess.Write, FileShare.Read);
+ await WriteByteAsync(fs, 42);
+ }));
+ }
+
+ private const int AF_UNIX = 1;
+ private const int SOCK_STREAM = 1;
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public unsafe void SocketPair_ReadWrite()
+ {
+ int* ptr = stackalloc int[2];
+ Assert.Equal(0, socketpair(AF_UNIX, SOCK_STREAM, 0, ptr));
+
+ using var readFileStream = new FileStream(new SafeFileHandle((IntPtr)ptr[0], ownsHandle: true), FileAccess.Read);
+ using var writeFileStream = new FileStream(new SafeFileHandle((IntPtr)ptr[1], ownsHandle: true), FileAccess.Write);
+
+ Task.WhenAll(
+ Task.Run(() => ReadByte(readFileStream, 42)),
+ Task.Run(() => WriteByte(writeFileStream, 42))).GetAwaiter().GetResult();
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Browser)]
+ public void SocketPair_ReadWrite_Async()
+ {
+ unsafe
+ {
+ int* ptr = stackalloc int[2];
+ Assert.Equal(0, socketpair(AF_UNIX, SOCK_STREAM, 0, ptr));
+
+ using var readFileStream = new FileStream(new SafeFileHandle((IntPtr)ptr[0], ownsHandle: true), FileAccess.Read);
+ using var writeFileStream = new FileStream(new SafeFileHandle((IntPtr)ptr[1], ownsHandle: true), FileAccess.Write);
+
+ Task.WhenAll(
+ ReadByteAsync(readFileStream, 42),
+ WriteByteAsync(writeFileStream, 42)).GetAwaiter().GetResult();
+ }
+ }
+
+ private static void ReadByte(FileStream fs, byte expected)
+ {
+ var buffer = new byte[1];
+ Assert.Equal(1, fs.Read(buffer));
+ Assert.Equal(expected, buffer[0]);
+ }
+
+ private static void WriteByte(FileStream fs, byte value)
+ {
+ fs.Write(new byte[] { value });
+ fs.Flush();
+ }
+
+ private static async Task ReadByteAsync(FileStream fs, byte expected)
+ {
+ var buffer = new byte[1];
+ Assert.Equal(1, await fs.ReadAsync(buffer));
+ Assert.Equal(expected, buffer[0]);
+ }
+
+ private static async Task WriteByteAsync(FileStream fs, byte value)
+ {
+ await fs.WriteAsync(new byte[] { value });
+ await fs.FlushAsync();
+ }
+
+ private static Lazy> AvailableDevicePaths = new Lazy>(() =>
+ {
+ List paths = new();
+ FileStreamOptions options = new() { Access = FileAccess.Write, Share = FileShare.Write };
+
+ foreach (string devicePath in new[] { "/dev/tty", "/dev/console", "/dev/null", "/dev/zero" })
+ {
+ if (!File.Exists(devicePath))
+ {
+ continue;
+ }
+
+ try
+ {
+ File.Open(devicePath, options).Dispose();
+ }
+ catch (Exception ex)
+ {
+ if (ex is IOException || ex is UnauthorizedAccessException)
+ {
+ continue;
+ }
+
+ throw;
+ }
+
+ paths.Add(devicePath);
+ }
+
+ return paths;
+ });
+
+ public static IEnumerable DevicePath_FileOptions_TestData()
+ {
+ foreach (string devicePath in AvailableDevicePaths.Value)
+ {
+ foreach (FileOptions options in new[] { FileOptions.None, FileOptions.Asynchronous })
+ {
+ yield return new object[] { devicePath, options};
+ }
+ }
+ }
+
+ public static IEnumerable DevicePath_TestData()
+ {
+ foreach (string devicePath in AvailableDevicePaths.Value)
+ {
+ yield return new object[] { devicePath };
+ }
+ }
+
+ [DllImport("libc")]
+ private static unsafe extern int socketpair(int domain, int type, int protocol, int* ptr);
+ }
+}
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs
index 4e2fb6fd2046e..af30be04c8673 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/ReadAsync.cs
@@ -101,7 +101,7 @@ public async Task ReadAsyncCanceledFile(int bufferSize, bool isAsync)
}
}
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported), nameof(PlatformDetection.IsNet5CompatFileStreamDisabled))]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[InlineData(FileShare.None, FileOptions.Asynchronous)] // FileShare.None: exclusive access
[InlineData(FileShare.ReadWrite, FileOptions.Asynchronous)] // FileShare.ReadWrite: others can write to the file, the length can't be cached
[InlineData(FileShare.None, FileOptions.None)]
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/SafeFileHandle.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/SafeFileHandle.cs
index 0740eed02f0d8..49b31884761ab 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/SafeFileHandle.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/SafeFileHandle.cs
@@ -65,89 +65,5 @@ public void AccessFlushesFileClosesHandle()
Assert.Equal(TestBuffer.Length, fsr.Length);
}
}
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNet5CompatFileStreamEnabled))]
- public async Task ThrowWhenHandlePositionIsChanged_sync()
- {
- await ThrowWhenHandlePositionIsChanged(useAsync: false);
- }
-
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported), nameof(PlatformDetection.IsNet5CompatFileStreamEnabled))]
- public async Task ThrowWhenHandlePositionIsChanged_async()
- {
- await ThrowWhenHandlePositionIsChanged(useAsync: true);
- }
-
- private async Task ThrowWhenHandlePositionIsChanged(bool useAsync)
- {
- string fileName = GetTestFilePath();
-
- using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 0x100, useAsync))
- {
- // write some data to move the position, flush to ensure OS position is updated
- fs.Write(TestBuffer, 0, TestBuffer.Length);
- fs.Flush();
-
- if (fs.SafeFileHandle.IsInvalid)
- {
- // nothing to test
- return;
- }
-
- using (FileStream fsr = new FileStream(fs.SafeFileHandle, FileAccess.Read, TestBuffer.Length, useAsync))
- {
- Assert.Equal(TestBuffer.Length, fs.Position);
- Assert.Equal(TestBuffer.Length, fsr.Position);
-
- // Operations on original filestream will fail if data is in buffer and position changes.
-
- // Put data in FS write buffer and update position from FSR
- fs.WriteByte(0);
- fsr.Position = 0;
-
- if (useAsync
- // Async I/O behaviors differ due to kernel-based implementation on Windows
- && OperatingSystem.IsWindows()
- // ReadAsync which in this case (single byte written to buffer) calls FlushAsync is now 100% async
- // so it does not complete synchronously anymore
- && PlatformDetection.IsNet5CompatFileStreamEnabled)
- {
- Assert.Throws(() => FSAssert.CompletesSynchronously(fs.ReadAsync(new byte[1], 0, 1)));
- }
- else
- {
- await Assert.ThrowsAsync(() => fs.ReadAsync(new byte[1], 0, 1));
- }
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.Read(new byte[1], 0, 1));
-
- fs.WriteByte(0);
- fsr.Position++;
- await Assert.ThrowsAsync(() => fs.ReadAsync(new byte[1], 0, 1));
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.ReadByte());
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.Seek(0, SeekOrigin.End));
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.SetLength(2));
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.Flush());
-
- fs.WriteByte(0);
- fsr.Position++;
- Assert.Throws(() => fs.Dispose());
- }
- }
- }
}
}
diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
index 06a9422589ee8..86eef052df1b4 100644
--- a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
@@ -229,18 +229,6 @@ public async Task ManyConcurrentWriteAsyncs_OuterLoop(
{
writes[i] = WriteAsync(fs, expectedData, i * writeSize, writeSize, cancellationToken);
Assert.Null(writes[i].Exception);
- if (useAsync)
- {
- // To ensure that the buffer of a FileStream opened for async IO is flushed
- // by FlushAsync in asynchronous way, we aquire a lock for every buffered WriteAsync.
- // The side effect of this is that the Position of FileStream is not updated until
- // the lock is released by a previous operation.
- // So now all WriteAsync calls should be awaited before starting another async file operation.
- if (PlatformDetection.IsNet5CompatFileStreamEnabled)
- {
- Assert.Equal((i + 1) * writeSize, fs.Position);
- }
- }
}
await Task.WhenAll(writes);
diff --git a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/Net5CompatSwitchTests.cs b/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/Net5CompatSwitchTests.cs
deleted file mode 100644
index fb70c4d3c47d0..0000000000000
--- a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/Net5CompatSwitchTests.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Reflection;
-using Xunit;
-
-namespace System.IO.Tests
-{
- public class Net5CompatSwitchTests
- {
- [Fact]
- public static void LegacySwitchIsHonored()
- {
- Assert.True(PlatformDetection.IsNet5CompatFileStreamEnabled);
-
- string filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
-
- using (FileStream fileStream = File.Create(filePath))
- {
- object strategy = fileStream
- .GetType()
- .GetField("_strategy", BindingFlags.NonPublic | BindingFlags.Instance)
- .GetValue(fileStream);
-
- Assert.Contains("Net5Compat", strategy.GetType().FullName);
- }
-
- File.Delete(filePath);
- }
- }
-}
diff --git a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/System.IO.FileSystem.Net5Compat.Tests.csproj b/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/System.IO.FileSystem.Net5Compat.Tests.csproj
deleted file mode 100644
index 54b9c2622937d..0000000000000
--- a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/System.IO.FileSystem.Net5Compat.Tests.csproj
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
- true
- true
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix
-
- --working-dir=/test-dir
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/runtimeconfig.template.json b/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/runtimeconfig.template.json
deleted file mode 100644
index 6e843517fe47a..0000000000000
--- a/src/libraries/System.IO.FileSystem/tests/Net5CompatTests/runtimeconfig.template.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "configProperties": {
- "System.IO.UseNet5CompatFileStream": true
- }
-}
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs
index 8bb39e4b2893f..ef60a9f223fb2 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/NoBuffering.Windows.cs
@@ -180,18 +180,17 @@ public async Task WriteAsyncUsingMultipleBuffers(bool asyncOperation, bool async
Assert.Equal(content, File.ReadAllBytes(filePath));
}
- [Fact]
- public async Task ReadWriteAsyncUsingNonPageSizedMultipleBuffers()
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task ReadWriteAsyncUsingMultipleBuffers(bool memoryPageSized)
{
string filePath = GetTestFilePath();
- // The Windows scatter/gather APIs accept segments that are exactly one page long.
- // Combined with the FILE_FLAG_NO_BUFFERING's requirements, the segments must also
- // be aligned at page size boundaries and have a size of a multiple of the page size.
- // Using segments with a length of twice the page size adheres to the second requirement
- // but not the first. The RandomAccess implementation will see it and issue sequential
- // read/write syscalls per segment, instead of one scatter/gather syscall.
- // This test verifies that fallback behavior.
- int bufferSize = Environment.SystemPageSize * 2;
+ // We test with buffers both one and two memory pages long. In the former case,
+ // the I/O operations will issue one scatter/gather API call, and in the latter
+ // case they will issue multiple calls; one per buffer. The buffers must still
+ // be aligned to comply with FILE_FLAG_NO_BUFFERING's requirements.
+ int bufferSize = Environment.SystemPageSize * (memoryPageSized ? 1 : 2);
int fileSize = bufferSize * 2;
byte[] content = RandomNumberGenerator.GetBytes(fileSize);
@@ -205,10 +204,22 @@ public async Task ReadWriteAsyncUsingNonPageSizedMultipleBuffers()
await RandomAccess.WriteAsync(handle, new ReadOnlyMemory[] { firstHalf, secondHalf }, 0);
buffer.GetSpan().Clear();
- await RandomAccess.ReadAsync(handle, new Memory[] { firstHalf, secondHalf }, 0);
+ long nRead = await RandomAccess.ReadAsync(handle, new Memory[] { firstHalf, secondHalf }, 0);
+
+ Assert.Equal(buffer.GetSpan().Length, nRead);
+ AssertExtensions.SequenceEqual(buffer.GetSpan(), content.AsSpan());
}
+ }
+
+ [Fact]
+ public async Task ReadWriteAsyncUsingEmptyBuffers()
+ {
+ string filePath = GetTestFilePath();
+ using SafeFileHandle handle = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, FileOptions.Asynchronous | NoBuffering);
- Assert.Equal(content, await File.ReadAllBytesAsync(filePath));
+ long nRead = await RandomAccess.ReadAsync(handle, Array.Empty>(), 0);
+ Assert.Equal(0, nRead);
+ await RandomAccess.WriteAsync(handle, Array.Empty>(), 0);
}
// when using FileOptions.Asynchronous we are testing Scatter&Gather APIs on Windows (FILE_FLAG_OVERLAPPED requirement)
diff --git a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
index 62245742929df..abf73ff35986c 100644
--- a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
+++ b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
@@ -119,6 +119,7 @@
+
diff --git a/src/libraries/System.IO.Ports/pkg/runtime.osx-arm64.runtime.native.System.IO.Ports.proj b/src/libraries/System.IO.Ports/pkg/runtime.osx-arm64.runtime.native.System.IO.Ports.proj
new file mode 100644
index 0000000000000..e6410bd635cd2
--- /dev/null
+++ b/src/libraries/System.IO.Ports/pkg/runtime.osx-arm64.runtime.native.System.IO.Ports.proj
@@ -0,0 +1,7 @@
+
+
+
+
+ true
+
+
diff --git a/src/libraries/System.IO/System.IO.sln b/src/libraries/System.IO/System.IO.sln
index 190c3aa32bae0..e4ba7a8f57e4f 100644
--- a/src/libraries/System.IO/System.IO.sln
+++ b/src/libraries/System.IO/System.IO.sln
@@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO", "ref\System.IO.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO", "src\System.IO.csproj", "{0769544B-1A5D-4D74-94FD-899DF6C39D62}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Net5Compat.Tests", "tests\Net5CompatTests\System.IO.Net5Compat.Tests.csproj", "{0217540D-FA86-41B3-9754-7BB5096ABA3E}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Tests", "tests\System.IO.Tests.csproj", "{72923407-7B7B-44A8-BCA6-2DB562835A8F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{602525FF-EE47-4938-8979-32DC962109E4}"
diff --git a/src/libraries/System.IO/tests/Net5CompatTests/System.IO.Net5Compat.Tests.csproj b/src/libraries/System.IO/tests/Net5CompatTests/System.IO.Net5Compat.Tests.csproj
deleted file mode 100644
index c07749abe26b0..0000000000000
--- a/src/libraries/System.IO/tests/Net5CompatTests/System.IO.Net5Compat.Tests.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- System.IO
- true
- true
- true
- $(NetCoreAppCurrent)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/libraries/System.IO/tests/Net5CompatTests/runtimeconfig.template.json b/src/libraries/System.IO/tests/Net5CompatTests/runtimeconfig.template.json
deleted file mode 100644
index 6e843517fe47a..0000000000000
--- a/src/libraries/System.IO/tests/Net5CompatTests/runtimeconfig.template.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "configProperties": {
- "System.IO.UseNet5CompatFileStream": true
- }
-}
diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs
index 1ddd8df16a6b5..a11ae2b6cf15b 100644
--- a/src/libraries/System.Memory/ref/System.Memory.cs
+++ b/src/libraries/System.Memory/ref/System.Memory.cs
@@ -314,6 +314,7 @@ public void Rewind(long count) { }
public bool TryReadTo(out System.ReadOnlySpan span, T delimiter, T delimiterEscape, bool advancePastDelimiter = true) { throw null; }
public bool TryReadToAny(out System.Buffers.ReadOnlySequence sequence, System.ReadOnlySpan delimiters, bool advancePastDelimiter = true) { throw null; }
public bool TryReadToAny(out System.ReadOnlySpan span, System.ReadOnlySpan delimiters, bool advancePastDelimiter = true) { throw null; }
+ public bool TryReadExact(int count, out System.Buffers.ReadOnlySequence sequence) { throw null; }
}
public readonly partial struct StandardFormat : System.IEquatable
{
diff --git a/src/libraries/System.Memory/src/System/Buffers/SequenceReader.Search.cs b/src/libraries/System.Memory/src/System/Buffers/SequenceReader.Search.cs
index af602ae6ae4a2..71a626dd80ed3 100644
--- a/src/libraries/System.Memory/src/System/Buffers/SequenceReader.Search.cs
+++ b/src/libraries/System.Memory/src/System/Buffers/SequenceReader.Search.cs
@@ -502,6 +502,32 @@ public bool TryReadTo(out ReadOnlySequence sequence, ReadOnlySpan delimite
return false;
}
+ ///
+ /// Try to read data with given .
+ ///
+ /// Read count.
+ /// The read data, if successfully read requested data.
+ /// true if remaining items in current is enough for .
+ public bool TryReadExact(int count, out ReadOnlySequence sequence)
+ {
+ if (count < 0)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
+ }
+ if (count > Remaining)
+ {
+ sequence = default;
+ return false;
+ }
+
+ sequence = Sequence.Slice(Position, count);
+ if (count != 0)
+ {
+ Advance(count);
+ }
+ return true;
+ }
+
///
/// Advance until the given , if found.
///
diff --git a/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs b/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
index 57ceb9e5985cf..b042eb9d556b8 100644
--- a/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
+++ b/src/libraries/System.Memory/tests/SequenceReader/ReadTo.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Linq;
using System.Buffers;
using Xunit;
@@ -107,6 +108,38 @@ public void TryReadTo_Sequence(bool advancePastDelimiter, bool useEscapeOverload
}
}
+ [Fact]
+ public void TryReadExact_Sequence()
+ {
+ ReadOnlySequence data = SequenceFactory.Create(new int[][] {
+ new int[] { 0 },
+ new int[] { 1, 2 },
+ new int[] { },
+ new int[] { 3, 4 }
+ });
+
+ var sequenceReader = new SequenceReader(data);
+
+ Assert.True(sequenceReader.TryReadExact(0, out ReadOnlySequence sequence));
+ Assert.Equal(0, sequence.Length);
+
+ for (int i = 0; i < 2; i++)
+ {
+ Assert.True(sequenceReader.TryReadExact(2, out sequence));
+ Assert.Equal(Enumerable.Range(i * 2, 2), sequence.ToArray());
+ }
+
+ // There is only 1 item in sequence reader
+ Assert.False(sequenceReader.TryReadExact(2, out _));
+
+ // The last 1 item was not advanced so still can be fetched
+ Assert.True(sequenceReader.TryReadExact(1, out sequence));
+ Assert.Equal(1, sequence.Length);
+ Assert.Equal(4, sequence.FirstSpan[0]);
+
+ Assert.True(sequenceReader.End);
+ }
+
[Theory,
InlineData(false),
InlineData(true),]
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
index 72051c9d1d800..498b04b0b135a 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
@@ -1305,7 +1305,8 @@ protected override void Dispose(bool disposing)
else
{
// We shouldn't be using a managed instance here, but don't have much choice -- we
- // need to remove the stream from the connection's GOAWAY collection.
+ // need to remove the stream from the connection's GOAWAY collection and properly abort.
+ stream.AbortStream();
stream._connection.RemoveStream(stream._stream);
stream._connection = null!;
}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
index e54798becb1d8..0430fdfb7ec3d 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Finalization.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Net.Quic;
using System.Net.Test.Common;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -27,9 +28,8 @@ private static Task GetAndDropResponse(HttpClient client, Uri url)
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
public async Task IncompleteResponseStream_ResponseDropped_CancelsRequestToServer()
{
- if (UseVersion == HttpVersion30)
+ if (UseQuicImplementationProvider == QuicImplementationProviders.Mock)
{
- // [ActiveIssue("https://github.com/dotnet/runtime/issues/58234")]
return;
}
diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs
index 60abf523ef0a2..66e594c34fca5 100644
--- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs
+++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicConnection.cs
@@ -283,6 +283,11 @@ private static uint HandleEventShutdownInitiatedByTransport(State state, ref Con
state.ConnectTcs = null;
}
+ // To throw QuicConnectionAbortedException (instead of QuicOperationAbortedException) out of AcceptStreamAsync() since
+ // it wasn't our side who shutdown the connection.
+ // We should rather keep the Status and propagate it either in a different exception or as a different field of QuicConnectionAbortedException.
+ // See: https://github.com/dotnet/runtime/issues/60133
+ state.AbortErrorCode = 0;
state.AcceptQueue.Writer.TryComplete();
return MsQuicStatusCodes.Success;
}
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
index 359078e59cd0b..c857ab33a1eee 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
@@ -1933,7 +1933,7 @@ public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName opti
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
}
@@ -2015,7 +2015,7 @@ public void SetRawSocketOption(int optionLevel, int optionName, ReadOnlySpan option
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
return realOptionLength;
@@ -3432,7 +3432,7 @@ internal unsafe void SetSocketOption(SocketOptionLevel optionLevel, SocketOption
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
}
@@ -3445,7 +3445,7 @@ private void SetMulticastOption(SocketOptionName optionName, MulticastOption MR)
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
}
@@ -3472,7 +3472,7 @@ private void SetLingerOption(LingerOption lref)
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
}
@@ -3486,7 +3486,7 @@ private void SetLingerOption(LingerOption lref)
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
return lingerOption;
@@ -3502,7 +3502,7 @@ private void SetLingerOption(LingerOption lref)
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
return multicastOption;
@@ -3519,7 +3519,7 @@ private void SetLingerOption(LingerOption lref)
// Throw an appropriate SocketException if the native call fails.
if (errorCode != SocketError.Success)
{
- UpdateStatusAfterSocketErrorAndThrowException(errorCode);
+ UpdateStatusAfterSocketOptionErrorAndThrowException(errorCode);
}
return multicastOption;
@@ -3690,11 +3690,19 @@ internal void SetToDisconnected()
}
}
- private void UpdateStatusAfterSocketErrorAndThrowException(SocketError error, [CallerMemberName] string? callerName = null)
+ private void UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError error, [CallerMemberName] string? callerName = null)
+ {
+ // Don't disconnect socket for unknown options.
+ bool disconnectOnFailure = error != SocketError.ProtocolOption &&
+ error != SocketError.OperationNotSupported;
+ UpdateStatusAfterSocketErrorAndThrowException(error, disconnectOnFailure, callerName);
+ }
+
+ private void UpdateStatusAfterSocketErrorAndThrowException(SocketError error, bool disconnectOnFailure = true, [CallerMemberName] string? callerName = null)
{
// Update the internal state of this socket according to the error before throwing.
var socketException = new SocketException((int)error);
- UpdateStatusAfterSocketError(socketException);
+ UpdateStatusAfterSocketError(socketException, disconnectOnFailure);
if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, socketException, memberName: callerName);
throw socketException;
}
@@ -3702,18 +3710,18 @@ private void UpdateStatusAfterSocketErrorAndThrowException(SocketError error, [C
// UpdateStatusAfterSocketError(socketException) - updates the status of a connected socket
// on which a failure occurred. it'll go to winsock and check if the connection
// is still open and if it needs to update our internal state.
- internal void UpdateStatusAfterSocketError(SocketException socketException)
+ internal void UpdateStatusAfterSocketError(SocketException socketException, bool disconnectOnFailure = true)
{
- UpdateStatusAfterSocketError(socketException.SocketErrorCode);
+ UpdateStatusAfterSocketError(socketException.SocketErrorCode, disconnectOnFailure);
}
- internal void UpdateStatusAfterSocketError(SocketError errorCode)
+ internal void UpdateStatusAfterSocketError(SocketError errorCode, bool disconnectOnFailure = true)
{
// If we already know the socket is disconnected
// we don't need to do anything else.
- if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, $"errorCode:{errorCode}");
+ if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, $"errorCode:{errorCode}, disconnectOnFailure:{disconnectOnFailure}");
- if (_isConnected && (_handle.IsInvalid || (errorCode != SocketError.WouldBlock &&
+ if (disconnectOnFailure && _isConnected && (_handle.IsInvalid || (errorCode != SocketError.WouldBlock &&
errorCode != SocketError.IOPending && errorCode != SocketError.NoBufferSpaceAvailable &&
errorCode != SocketError.TimedOut)))
{
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs
index e6868e4a6fbeb..5073f60c3e6a1 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs
@@ -562,6 +562,132 @@ public void Get_AcceptConnection_Succeeds()
}
}
+ [Fact]
+ public void GetUnsupportedSocketOption_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ SocketException se = Assert.Throws(() => socket1.GetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1)));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void GetUnsupportedSocketOptionBytesArg_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ var optionValue = new byte[4];
+ SocketException se = Assert.Throws(() => socket1.GetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1), optionValue));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void GetUnsupportedSocketOptionLengthArg_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ SocketException se = Assert.Throws(() => socket1.GetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1), optionLength: 4));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void SetUnsupportedSocketOptionIntArg_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ SocketException se = Assert.Throws(() => socket1.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1), optionValue: 1));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void SetUnsupportedSocketOptionBytesArg_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ var optionValue = new byte[4];
+ SocketException se = Assert.Throws(() => socket1.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1), optionValue));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void SetUnsupportedSocketOptionBoolArg_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ bool optionValue = true;
+ SocketException se = Assert.Throws(() => socket1.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)(-1), optionValue));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void GetUnsupportedRawSocketOption_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ var optionValue = new byte[4];
+ SocketException se = Assert.Throws(() => socket1.GetRawSocketOption(SOL_SOCKET, -1, optionValue));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ [Fact]
+ public void SetUnsupportedRawSocketOption_DoesNotDisconnectSocket()
+ {
+ (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair();
+ using (socket1)
+ using (socket2)
+ {
+ var optionValue = new byte[4];
+ SocketException se = Assert.Throws(() => socket1.SetRawSocketOption(SOL_SOCKET, -1, optionValue));
+ Assert.True(se.SocketErrorCode == SocketError.ProtocolOption ||
+ se.SocketErrorCode == SocketError.OperationNotSupported, $"SocketError: {se.SocketErrorCode}");
+
+ Assert.True(socket1.Connected, "Connected");
+ }
+ }
+
+ private static int SOL_SOCKET = OperatingSystem.IsLinux() ? 1 : (int)SocketOptionLevel.Socket;
}
[Collection("NoParallelTests")]
diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs
index 9e400c3f723a9..752ca8ece8189 100644
--- a/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs
+++ b/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs
@@ -22,7 +22,7 @@ public async Task ConnectAsync_Cancel_ThrowsCancellationException(Uri server)
var cts = new CancellationTokenSource(100);
var ub = new UriBuilder(server);
- ub.Query = "delay20sec";
+ ub.Query = PlatformDetection.IsBrowser ? "delay20sec" : "delay10sec";
var ex = await Assert.ThrowsAnyAsync(() => cws.ConnectAsync(ub.Uri, cts.Token));
Assert.True(WebSocketState.Closed == cws.State, $"Actual {cws.State} when {ex}");
diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs
index f861739278f95..556e6672b806c 100644
--- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs
+++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs
@@ -958,8 +958,10 @@ private void TestToString(string format, IFormatProvider provider) where T :
[Fact]
public void AdditionInt64() { TestAddition(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AdditionSingle() { TestAddition(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AdditionDouble() { TestAddition(); }
private void TestAddition() where T : struct
{
@@ -1023,8 +1025,10 @@ private void TestAdditionOverflow() where T : struct
[Fact]
public void SubtractionInt64() { TestSubtraction(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void SubtractionSingle() { TestSubtraction(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void SubtractionDouble() { TestSubtraction(); }
private void TestSubtraction() where T : struct
{
@@ -1088,8 +1092,10 @@ private void TestSubtractionOverflow() where T : struct
[Fact]
public void MultiplicationInt64() { TestMultiplication(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationSingle() { TestMultiplication(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationDouble() { TestMultiplication(); }
private void TestMultiplication() where T : struct
{
@@ -1122,8 +1128,10 @@ private void TestMultiplication() where T : struct
[Fact]
public void MultiplicationWithScalarInt64() { TestMultiplicationWithScalar(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationWithScalarSingle() { TestMultiplicationWithScalar(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationWithScalarDouble() { TestMultiplicationWithScalar(); }
private void TestMultiplicationWithScalar() where T : struct
{
@@ -1164,8 +1172,10 @@ private void TestMultiplicationWithScalar() where T : struct
[Fact]
public void DivisionInt64() { TestDivision(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DivisionSingle() { TestDivision(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DivisionDouble() { TestDivision(); }
private void TestDivision() where T : struct
{
@@ -1224,8 +1234,10 @@ private void TestDivisionByZeroException() where T : struct
[Fact]
public void UnaryMinusInt64() { TestUnaryMinus(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void UnaryMinusSingle() { TestUnaryMinus(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void UnaryMinusDouble() { TestUnaryMinus(); }
private void TestUnaryMinus() where T : struct
{
@@ -1424,8 +1436,10 @@ private void TestBitwiseAndNot() where T : struct
[Fact]
public void VectorGreaterThanInt64() { TestVectorGreaterThan(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void VectorGreaterThanSingle() { TestVectorGreaterThan(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void VectorGreaterThanDouble() { TestVectorGreaterThan(); }
private void TestVectorGreaterThan() where T : struct
{
@@ -1461,8 +1475,10 @@ private void TestVectorGreaterThan() where T : struct
[Fact]
public void GreaterThanOrEqualInt64() { TestVectorGreaterThanOrEqual(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void GreaterThanOrEqualSingle() { TestVectorGreaterThanOrEqual(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void GreaterThanOrEqualDouble() { TestVectorGreaterThanOrEqual(); }
private void TestVectorGreaterThanOrEqual() where T : struct
{
@@ -1714,8 +1730,10 @@ private void TestVectorGreaterThanOrEqualAll() where T : struct
[Fact]
public void LessThanInt64() { TestVectorLessThan(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanSingle() { TestVectorLessThan(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanDouble() { TestVectorLessThan(); }
private void TestVectorLessThan() where T : struct
{
@@ -1751,8 +1769,10 @@ private void TestVectorLessThan() where T : struct
[Fact]
public void LessThanOrEqualInt64() { TestVectorLessThanOrEqual(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanOrEqualSingle() { TestVectorLessThanOrEqual(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanOrEqualDouble() { TestVectorLessThanOrEqual(); }
private void TestVectorLessThanOrEqual() where T : struct
{
@@ -1788,8 +1808,10 @@ private void TestVectorLessThanOrEqual() where T : struct
[Fact]
public void LessThanAnyInt64() { TestVectorLessThanAny(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanAnySingle() { TestVectorLessThanAny(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void LessThanAnyDouble() { TestVectorLessThanAny(); }
private void TestVectorLessThanAny() where T : struct
{
@@ -2114,8 +2136,10 @@ private void TestVectorEqualsAll() where T : struct
[Fact]
public void ConditionalSelectInt64() { TestConditionalSelect(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void ConditionalSelectSingle() { TestConditionalSelect(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void ConditionalSelectDouble() { TestConditionalSelect(); }
private void TestConditionalSelect() where T : struct
{
@@ -2166,8 +2190,10 @@ private void TestConditionalSelect() where T : struct
[Fact]
public void DotProductInt64() { TestDotProduct(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DotProductSingle() { TestDotProduct(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DotProductDouble() { TestDotProduct(); }
private void TestDotProduct() where T : struct
{
@@ -2202,8 +2228,10 @@ private void TestDotProduct() where T : struct
[Fact]
public void MaxInt64() { TestMax(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MaxSingle() { TestMax(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MaxDouble() { TestMax(); }
private void TestMax() where T : struct
{
@@ -2238,8 +2266,10 @@ private void TestMax() where T : struct
[Fact]
public void MinInt64() { TestMin(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MinSingle() { TestMin(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MinDouble() { TestMin(); }
private void TestMin() where T : struct
{
@@ -2274,8 +2304,10 @@ private void TestMin() where T : struct
[Fact]
public void SquareRootInt64() { TestSquareRoot(-1); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void SquareRootSingle() { TestSquareRoot(6); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void SquareRootDouble() { TestSquareRoot(15); }
private void TestSquareRoot(int precision = -1) where T : struct, IEquatable
{
@@ -2368,8 +2400,10 @@ public void FloorDouble()
[Fact]
public void AbsInt64() { TestAbs(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AbsSingle() { TestAbs(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AbsDouble() { TestAbs(); }
private void TestAbs() where T : struct
{
@@ -2406,8 +2440,10 @@ private void TestAbs() where T : struct
[Fact]
public void MultiplicationReflectionInt64() { TestMultiplicationReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationReflectionSingle() { TestMultiplicationReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void MultiplicationReflectionDouble() { TestMultiplicationReflection(); }
private void TestMultiplicationReflection() where T : struct
{
@@ -2443,8 +2479,10 @@ private void TestMultiplicationReflection() where T : struct
[Fact]
public void AdditionReflectionInt64() { TestAdditionReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AdditionReflectionSingle() { TestAdditionReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void AdditionReflectionDouble() { TestAdditionReflection(); }
private void TestAdditionReflection() where T : struct
{
@@ -2480,8 +2518,10 @@ private void TestAdditionReflection() where T : struct
[Fact]
public void DivisionReflectionInt64() { TestDivisionReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DivisionReflectionSingle() { TestDivisionReflection(); }
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/60347", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoRuntime), nameof(PlatformDetection.IsX86Process))]
public void DivisionReflectionDouble() { TestDivisionReflection(); }
private void TestDivisionReflection() where T : struct
{
diff --git a/src/libraries/System.Numerics.Vectors/tests/Util.cs b/src/libraries/System.Numerics.Vectors/tests/Util.cs
index 4fb55a716afd1..135b3fc0e65e4 100644
--- a/src/libraries/System.Numerics.Vectors/tests/Util.cs
+++ b/src/libraries/System.Numerics.Vectors/tests/Util.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Linq;
-
namespace System.Numerics.Tests
{
public static class Util
@@ -93,57 +91,150 @@ public static T GenerateSingleValue(int min = 1, int max = 100) where T : str
public static T Abs(T value) where T : struct
{
- Type[] unsignedTypes = new[] { typeof(byte), typeof(ushort), typeof(uint), typeof(ulong) };
- if (unsignedTypes.Contains(typeof(T)))
- {
- return value;
- }
-
- dynamic dyn = (dynamic)value;
- var abs = Math.Abs(dyn);
- T ret = (T)abs;
- return ret;
+ // unsigned types
+ if (value is byte) return value;
+ else if (value is ushort) return value;
+ else if (value is uint) return value;
+ else if (value is ulong) return value;
+ // signed types
+ else if (value is short) return (T)(ValueType)(short) ( Math.Abs((short) (ValueType)value) );
+ else if (value is int) return (T)(ValueType)(int) ( Math.Abs((int) (ValueType)value) );
+ else if (value is long) return (T)(ValueType)(long) ( Math.Abs((long) (ValueType)value) );
+ else if (value is sbyte) return (T)(ValueType)(sbyte) ( Math.Abs((sbyte) (ValueType)value) );
+ else if (value is float) return (T)(ValueType)(float) ( Math.Abs((float) (ValueType)value) );
+ else if (value is double) return (T)(ValueType)(double) ( Math.Abs((double)(ValueType)value) );
+ else throw new NotImplementedException();
}
public static T Sqrt(T value) where T : struct
{
- return unchecked((T)(dynamic)(Math.Sqrt((dynamic)value)));
+ unchecked
+ {
+ if (value is short) return (T)(ValueType)(short) ( Math.Sqrt((short) (ValueType)value) );
+ else if (value is int) return (T)(ValueType)(int) ( Math.Sqrt((int) (ValueType)value) );
+ else if (value is long) return (T)(ValueType)(long) ( Math.Sqrt((long) (ValueType)value) );
+ else if (value is ushort) return (T)(ValueType)(ushort) ( Math.Sqrt((ushort)(ValueType)value) );
+ else if (value is uint) return (T)(ValueType)(uint) ( Math.Sqrt((uint) (ValueType)value) );
+ else if (value is ulong) return (T)(ValueType)(ulong) ( Math.Sqrt((ulong) (ValueType)value) );
+ else if (value is byte) return (T)(ValueType)(byte) ( Math.Sqrt((byte) (ValueType)value) );
+ else if (value is sbyte) return (T)(ValueType)(sbyte) ( Math.Sqrt((sbyte) (ValueType)value) );
+ else if (value is float) return (T)(ValueType)(float) ( Math.Sqrt((float) (ValueType)value) );
+ else if (value is double) return (T)(ValueType)(double) ( Math.Sqrt((double)(ValueType)value) );
+ else throw new NotImplementedException();
+ }
}
public static T Multiply(T left, T right) where T : struct
{
- return unchecked((T)((dynamic)left * right));
+ unchecked
+ {
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left * (short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left * (int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left * (long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left * (ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left * (uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left * (ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left * (byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left * (sbyte) (ValueType)right );
+ else if (left is float) return (T)(ValueType)(float) ( (float) (ValueType)left * (float) (ValueType)right );
+ else if (left is double) return (T)(ValueType)(double) ( (double)(ValueType)left * (double)(ValueType)right );
+ else throw new NotImplementedException();
+ }
}
public static T Divide(T left, T right) where T : struct
{
- return (T)((dynamic)left / right);
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left / (short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left / (int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left / (long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left / (ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left / (uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left / (ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left / (byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left / (sbyte) (ValueType)right );
+ else if (left is float) return (T)(ValueType)(float) ( (float) (ValueType)left / (float) (ValueType)right );
+ else if (left is double) return (T)(ValueType)(double) ( (double)(ValueType)left / (double)(ValueType)right );
+ else throw new NotImplementedException();
}
public static T Add(T left, T right) where T : struct
{
- return unchecked((T)((dynamic)left + right));
+ unchecked
+ {
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left + (short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left + (int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left + (long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left + (ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left + (uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left + (ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left + (byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left + (sbyte) (ValueType)right );
+ else if (left is float) return (T)(ValueType)(float) ( (float) (ValueType)left + (float) (ValueType)right );
+ else if (left is double) return (T)(ValueType)(double) ( (double)(ValueType)left + (double)(ValueType)right );
+ else throw new NotImplementedException();
+ }
}
public static T Subtract(T left, T right) where T : struct
{
- return unchecked((T)((dynamic)left - right));
+ unchecked
+ {
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left - (short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left - (int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left - (long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left - (ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left - (uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left - (ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left - (byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left - (sbyte) (ValueType)right );
+ else if (left is float) return (T)(ValueType)(float) ( (float) (ValueType)left - (float) (ValueType)right );
+ else if (left is double) return (T)(ValueType)(double) ( (double)(ValueType)left - (double)(ValueType)right );
+ else throw new NotImplementedException();
+ }
}
public static T Xor(T left, T right) where T : struct
{
- return (T)((dynamic)left ^ right);
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left ^ (short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left ^ (int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left ^ (long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left ^ (ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left ^ (uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left ^ (ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left ^ (byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left ^ (sbyte) (ValueType)right );
+ else throw new NotImplementedException();
}
public static T AndNot(T left, T right) where T : struct
{
- return (T)((dynamic)left & ~(dynamic)right);
+ if (left is short) return (T)(ValueType)(short) ( (short) (ValueType)left & ~(short) (ValueType)right );
+ else if (left is int) return (T)(ValueType)(int) ( (int) (ValueType)left & ~(int) (ValueType)right );
+ else if (left is long) return (T)(ValueType)(long) ( (long) (ValueType)left & ~(long) (ValueType)right );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( (ushort)(ValueType)left & ~(ushort)(ValueType)right );
+ else if (left is uint) return (T)(ValueType)(uint) ( (uint) (ValueType)left & ~(uint) (ValueType)right );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( (ulong) (ValueType)left & ~(ulong) (ValueType)right );
+ else if (left is byte) return (T)(ValueType)(byte) ( (byte) (ValueType)left & ~(byte) (ValueType)right );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( (sbyte) (ValueType)left & ~(sbyte) (ValueType)right );
+ else throw new NotImplementedException();
}
public static T OnesComplement(T left) where T : struct
{
- return unchecked((T)(~(dynamic)left));
+ unchecked
+ {
+ if (left is short) return (T)(ValueType)(short) ( ~(short) (ValueType)left );
+ else if (left is int) return (T)(ValueType)(int) ( ~(int) (ValueType)left );
+ else if (left is long) return (T)(ValueType)(long) ( ~(long) (ValueType)left );
+ else if (left is ushort) return (T)(ValueType)(ushort) ( ~(ushort)(ValueType)left );
+ else if (left is uint) return (T)(ValueType)(uint) ( ~(uint) (ValueType)left );
+ else if (left is ulong) return (T)(ValueType)(ulong) ( ~(ulong) (ValueType)left );
+ else if (left is byte) return (T)(ValueType)(byte) ( ~(byte) (ValueType)left );
+ else if (left is sbyte) return (T)(ValueType)(sbyte) ( ~(sbyte) (ValueType)left );
+ else throw new NotImplementedException();
+ }
}
+
public static float Clamp(float value, float min, float max)
{
return value > max ? max : value < min ? min : value;
@@ -151,36 +242,92 @@ public static float Clamp(float value, float min, float max)
public static T Zero() where T : struct
{
- return (T)(dynamic)0;
+ if (typeof(T) == typeof(short)) return (T)(ValueType)(short) 0;
+ else if (typeof(T) == typeof(int)) return (T)(ValueType)(int) 0;
+ else if (typeof(T) == typeof(long)) return (T)(ValueType)(long) 0;
+ else if (typeof(T) == typeof(ushort)) return (T)(ValueType)(ushort) 0;
+ else if (typeof(T) == typeof(uint)) return (T)(ValueType)(uint) 0;
+ else if (typeof(T) == typeof(ulong)) return (T)(ValueType)(ulong) 0;
+ else if (typeof(T) == typeof(byte)) return (T)(ValueType)(byte) 0;
+ else if (typeof(T) == typeof(sbyte)) return (T)(ValueType)(sbyte) 0;
+ else if (typeof(T) == typeof(float)) return (T)(ValueType)(float) 0;
+ else if (typeof(T) == typeof(double)) return (T)(ValueType)(double) 0;
+ else throw new NotImplementedException();
}
public static T One() where T : struct
{
- return (T)(dynamic)1;
+ if (typeof(T) == typeof(short)) return (T)(ValueType)(short) 1;
+ else if (typeof(T) == typeof(int)) return (T)(ValueType)(int) 1;
+ else if (typeof(T) == typeof(long)) return (T)(ValueType)(long) 1;
+ else if (typeof(T) == typeof(ushort)) return (T)(ValueType)(ushort) 1;
+ else if (typeof(T) == typeof(uint)) return (T)(ValueType)(uint) 1;
+ else if (typeof(T) == typeof(ulong)) return (T)(ValueType)(ulong) 1;
+ else if (typeof(T) == typeof(byte)) return (T)(ValueType)(byte) 1;
+ else if (typeof(T) == typeof(sbyte)) return (T)(ValueType)(sbyte) 1;
+ else if (typeof(T) == typeof(float)) return (T)(ValueType)(float) 1;
+ else if (typeof(T) == typeof(double)) return (T)(ValueType)(double) 1;
+ else throw new NotImplementedException();
}
public static bool GreaterThan(T left, T right) where T : struct
{
- var result = (dynamic)left > right;
- return (bool)result;
+ if (left is short) return (short)(ValueType) left > (short)(ValueType) right;
+ else if (left is int) return (int)(ValueType) left > (int)(ValueType) right;
+ else if (left is long) return (long)(ValueType) left > (long)(ValueType) right;
+ else if (left is ushort) return (ushort)(ValueType) left > (ushort)(ValueType) right;
+ else if (left is uint) return (uint)(ValueType) left > (uint)(ValueType) right;
+ else if (left is ulong) return (ulong)(ValueType) left > (ulong)(ValueType) right;
+ else if (left is byte) return (byte)(ValueType) left > (byte)(ValueType) right;
+ else if (left is sbyte) return (sbyte)(ValueType) left > (sbyte)(ValueType) right;
+ else if (left is float) return (float)(ValueType) left > (float)(ValueType) right;
+ else if (left is double) return (double)(ValueType) left > (double)(ValueType) right;
+ else throw new NotImplementedException();
}
public static bool GreaterThanOrEqual(T left, T right) where T : struct
{
- var result = (dynamic)left >= right;
- return (bool)result;
+ if (left is short) return (short)(ValueType) left >= (short)(ValueType) right;
+ else if (left is int) return (int)(ValueType) left >= (int)(ValueType) right;
+ else if (left is long) return (long)(ValueType) left >= (long)(ValueType) right;
+ else if (left is ushort) return (ushort)(ValueType) left >= (ushort)(ValueType) right;
+ else if (left is uint) return (uint)(ValueType) left >= (uint)(ValueType) right;
+ else if (left is ulong) return (ulong)(ValueType) left >= (ulong)(ValueType) right;
+ else if (left is byte) return (byte)(ValueType) left >= (byte)(ValueType) right;
+ else if (left is sbyte) return (sbyte)(ValueType) left >= (sbyte)(ValueType) right;
+ else if (left is float) return (float)(ValueType) left >= (float)(ValueType) right;
+ else if (left is double) return (double)(ValueType) left >= (double)(ValueType) right;
+ else throw new NotImplementedException();
}
public static bool LessThan(T left, T right) where T : struct
{
- var result = (dynamic)left < right;
- return (bool)result;
+ if (left is short) return (short)(ValueType) left < (short)(ValueType) right;
+ else if (left is int) return (int)(ValueType) left < (int)(ValueType) right;
+ else if (left is long) return (long)(ValueType) left < (long)(ValueType) right;
+ else if (left is ushort) return (ushort)(ValueType) left < (ushort)(ValueType) right;
+ else if (left is uint) return (uint)(ValueType) left < (uint)(ValueType) right;
+ else if (left is ulong) return (ulong)(ValueType) left < (ulong)(ValueType) right;
+ else if (left is byte) return (byte)(ValueType) left < (byte)(ValueType) right;
+ else if (left is sbyte) return (sbyte)(ValueType) left < (sbyte)(ValueType) right;
+ else if (left is float) return (float)(ValueType) left < (float)(ValueType) right;
+ else if (left is double) return (double)(ValueType) left < (double)(ValueType) right;
+ else throw new NotImplementedException();
}
public static bool LessThanOrEqual(T left, T right) where T : struct
{
- var result = (dynamic)left <= right;
- return (bool)result;
+ if (left is short) return (short)(ValueType) left <= (short)(ValueType) right;
+ else if (left is int) return (int)(ValueType) left <= (int)(ValueType) right;
+ else if (left is long) return (long)(ValueType) left <= (long)(ValueType) right;
+ else if (left is ushort) return (ushort)(ValueType) left <= (ushort)(ValueType) right;
+ else if (left is uint) return (uint)(ValueType) left <= (uint)(ValueType) right;
+ else if (left is ulong) return (ulong)(ValueType) left <= (ulong)(ValueType) right;
+ else if (left is byte) return (byte)(ValueType) left <= (byte)(ValueType) right;
+ else if (left is sbyte) return (sbyte)(ValueType) left <= (sbyte)(ValueType) right;
+ else if (left is float) return (float)(ValueType) left <= (float)(ValueType) right;
+ else if (left is double) return (double)(ValueType) left <= (double)(ValueType) right;
+ else throw new NotImplementedException();
}
public static bool AnyEqual(T[] left, T[] right) where T : struct
diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
index 9f689b161bbd0..c2eab851bd60e 100644
--- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs
@@ -86,8 +86,11 @@ internal static Exception GetIOError(int errorCode, string? path)
_bufferSize = memory.Length;
_memoryHandle = memory.Pin();
_overlapped = _fileHandle.ThreadPoolBinding!.AllocateNativeOverlapped(_preallocatedOverlapped);
- _overlapped->OffsetLow = (int)fileOffset;
- _overlapped->OffsetHigh = (int)(fileOffset >> 32);
+ if (_fileHandle.CanSeek)
+ {
+ _overlapped->OffsetLow = (int)fileOffset;
+ _overlapped->OffsetHigh = (int)(fileOffset >> 32);
+ }
return _overlapped;
}
diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
index 9b38d148b2693..13847032fbec7 100644
--- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
@@ -16,6 +16,7 @@ public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
// not using bool? as it's not thread safe
private volatile NullableBool _canSeek = NullableBool.Undefined;
+ private volatile NullableBool _supportsRandomAccess = NullableBool.Undefined;
private bool _deleteOnClose;
private bool _isLocked;
@@ -33,6 +34,25 @@ private SafeFileHandle(bool ownsHandle)
internal bool CanSeek => !IsClosed && GetCanSeek();
+ internal bool SupportsRandomAccess
+ {
+ get
+ {
+ NullableBool supportsRandomAccess = _supportsRandomAccess;
+ if (supportsRandomAccess == NullableBool.Undefined)
+ {
+ _supportsRandomAccess = supportsRandomAccess = GetCanSeek() ? NullableBool.True : NullableBool.False;
+ }
+
+ return supportsRandomAccess == NullableBool.True;
+ }
+ set
+ {
+ Debug.Assert(value == false); // We should only use the setter to disable random access.
+ _supportsRandomAccess = value ? NullableBool.True : NullableBool.False;
+ }
+ }
+
internal ThreadPoolBoundHandle? ThreadPoolBinding => null;
internal void EnsureThreadPoolBindingInitialized() { /* nop */ }
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 867e13262ba6a..68f5c3af638c5 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -462,7 +462,6 @@
-
@@ -1846,8 +1845,6 @@
-
-
@@ -2136,7 +2133,6 @@
-
diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
index 5e047136ae753..a22d6ff385c08 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs
@@ -285,11 +285,11 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
// IAdditionOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IAdditionOperators.operator +(byte left, byte right)
=> (byte)(left + right);
- // [RequiresPreviewFeatures]
+ // [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
// static checked byte IAdditionOperators.operator +(byte left, byte right)
// => checked((byte)(left + right));
@@ -297,30 +297,30 @@ object IConvertible.ToType(Type type, IFormatProvider? provider)
// IAdditiveIdentity
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IAdditiveIdentity.AdditiveIdentity => 0;
//
// IBinaryInteger
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.LeadingZeroCount(byte value)
=> (byte)(BitOperations.LeadingZeroCount(value) - 24);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.PopCount(byte value)
=> (byte)BitOperations.PopCount(value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.RotateLeft(byte value, int rotateAmount)
=> (byte)((value << (rotateAmount & 7)) | (value >> ((8 - rotateAmount) & 7)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.RotateRight(byte value, int rotateAmount)
=> (byte)((value >> (rotateAmount & 7)) | (value << ((8 - rotateAmount) & 7)));
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryInteger.TrailingZeroCount(byte value)
=> (byte)(BitOperations.TrailingZeroCount(value << 24) - 24);
@@ -328,11 +328,11 @@ static byte IBinaryInteger.TrailingZeroCount(byte value)
// IBinaryNumber
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static bool IBinaryNumber.IsPow2(byte value)
=> BitOperations.IsPow2((uint)value);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBinaryNumber.Log2(byte value)
=> (byte)BitOperations.Log2(value);
@@ -340,19 +340,19 @@ static byte IBinaryNumber.Log2(byte value)
// IBitwiseOperators
//
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator &(byte left, byte right)
=> (byte)(left & right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators.operator |(byte left, byte right)
=> (byte)(left | right);
- [RequiresPreviewFeatures]
+ [RequiresPreviewFeatures(Number.PreviewFeatureMessage, Url = Number.PreviewFeatureUrl)]
static byte IBitwiseOperators