Merge pull request #6439 from dotnet/master

Merge master to nmirror
This commit is contained in:
Michal Strehovský 2018-10-10 10:05:55 -07:00 коммит произвёл GitHub
Родитель 624ff82bb6 57a2c9ce4d
Коммит d188cfe0e8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
51 изменённых файлов: 2515 добавлений и 1040 удалений

Просмотреть файл

@ -0,0 +1,189 @@
# ILC Compiler Architecture
Author: Michal Strehovsky ([@MichalStrehovsky](https://github.com/MichalStrehovsky)) - 2018
ILC (IL Compiler) is an ahead of time compiler that transforms programs in CIL (Common Intermediate Language) into a target language or instruction set to be executed on the CoreRT runtime (or CoreCLR runtime, in the future). The input to ILC is the common instruction format generated by popular managed language compilers such as C#, VB.NET, or F#. The output of ILC is native code for the target platform, along with data structures required to support executing the code on the target runtime. With a bit of stretch, one could say that ILC is an ahead of time native compiler for C#.
Traditionally, CIL has been compiled "just in time" (JIT). What this means is that the translation from CIL to the instruction set executable on the target runtime environment happened on an as-needed basis when the native code became necessary to continue execution of the program (e.g. on a first call to a CIL method). An ahead of time compiler tries to prepare the code and data structures in advance - before the program starts executing. The major advantages of having native code and data structures required for the code to execute available in advance are significant improvements to program startup time and working set.
In a fully ahead of time compiled environment, the compiler is responsible for generating code and data structures for everything that might be needed at runtime - the presence of the original CIL instructions or program metadata (names of methods and their signature, for example) is no longer necessary after compilation. One important aspect to keep in mind is that ahead of time compilation does not preclude just in time compilation: one could imagine mixed modes of execution where some parts of the application are compiled ahead of time, while others are compiled just in time, or interpreted. ILC needs to support such modes of operations, since both have their advantages and disadvantages. We have prototyped such modes of execution in the past.
## Goals
* Compile CIL and produce native code for the target platform
* Generate essential data structures that the runtime requires to execute managed native code (exception handling and GC information for methods, data structures describing types, their GC layout and vtables, interface dispatch maps, etc.)
* Generate optional data structures the base class libraries require to provide rich managed APIs to user code (data structures that support reflection, interop, textual stack trace information, type loading at runtime, etc.)
* Support optional inputs from a whole program analysis step to influence compilation
* Support generating executable files and static/dynamic libraries (with a flat C-style public API surface)
* Support multiple modes of compilation:
* Single-file output:
* All input assemblies merged into a single object file generated by ILC (merging managed assemblies happens in ILC). This mode allows maximum optimization.
* Generating multiple object files that are merged using a platform linker into a single executable (merging happens in the native linker after ILC runs). This mode allows incremental compilation at the cost of inhibiting optimizations in ILC.
* Multi-file output (one or more input assemblies generating one or more dynamic libraries that link against each other dynamically). This mode allows code/data sharing among several executables or dynamic libraries, but inhibits many optimizations.
* Multi-threaded compilation [not yet implemented]
* Generate native debug information for the target platform to allow debugging with native debuggers
* Generate outputs in the platform's native object file format (`.obj` and `.o` files)
* Have a defined behavior when input is incomplete (e.g. assemblies missing, or an assembly version mismatch)
## ILC composition
ILC is composed of roughly 3 parts: the compilation driver, the compiler, and the code generation backends.
### Compilation driver
The role of the compilation driver is to parse command line arguments, set up the compiler, and run the compilation. The process of setting up the compiler involves configuring a `CompilationBuilder`. The compilation builder exposes methods that let the driver configure and compose various pieces of the compiler as directed by the command line arguments. These components influence what gets compiled and how the compilation happens. Eventually the driver constructs a `Compilation` object that provides methods to run the compilation, inspect the results of the compilation, and write the outputs to a file on disk.
Related classes: `CompilationBuilder`, `ICompilation`
### Compiler
Compiler is the core component that the rest of the document is going to talk about. It's responsible for running the compilation process and generating data structures for the target runtime and target base class libraries.
The compiler tries to stay policy free as to what to compile, what data structures to generate, and how to do the compilation. The specific policies are supplied by the compilation driver as part of configuring the compilation.
### Code generation backends
ILC is designed to support multiple code generation backends that target the same runtime. What this means is that we have a model where there are common parts within the compiler (determining what needs to be compiled, generating data structures for the underlying runtime), and parts that are specific for a target environment. The common parts (the data structure layout) are not target specific - the target specific differences are limited to general questions, such as "does the target have representation for relative pointers?", but the basic shape of the data structures is the same, no matter the target platform.
ILC currently supports following codegen backends (with varying levels of completeness):
* **RyuJIT**: native code generator also used as the JIT compiler in CoreCLR. This backend supports x64, arm64, arm32 on Windows, Linux, macOS, and BSD.
* **CppCodegen**: a portable code generator that translates CIL into C++ code. This supports rapid platform bringup (instead of having to build a code generator for a new CPU architecture, it relies on the C++ compiler the platform likely already has). Portability comes at certain costs.
* **LLVM**: the LLVM backend is currently used to generate WebAssembly code in connection with Emscripten.
This document describes the common parts of the compiler that are applicable to all codegen backends.
Related project files: ILCompiler.CppCodegen.csproj, ILCompiler.WebAssembly.csproj
## Dependency analysis
The core concept driving the compilation in ILC is dependency analysis. Dependency analysis is the process of determining the set of runtime artifacts (method code bodies and various data structures) that need to be generated into the output object file. Dependency analysis builds a graph where each vertex either
* represents an artifact that will be part of the output file (such as "compiled method body" or "data structure describing a type at runtime") - this is an "object node", or
* captures certain abstract characteristic of the compiled program (such as "the program contains a virtual call to the `Object.GetHashCode` method") - a general "dependency node". General dependency nodes do not physically manifest themselves as bytes in the output, but they usually have edges that (transitively) lead to object nodes that do form parts of the output.
The edges of the graph represent a "requires" relationship. The compilation process corresponds to building this graph and determining what nodes are part of the graph.
Related classes: `DependencyNodeCore<>`, `ObjectNode`
Related project files and tests: ILCompiler.DependencyAnalysisFramework.csproj, ILCompiler.DependencyAnalysisFramework.Tests.csproj
### Dependency expansion process
The compilation starts with a set of nodes in the dependency graph called compilation roots. The roots are specified by the compilation driver and typically contain the `Main()` method, but the exact set of roots depends on the compilation mode: the set of roots will be different when we're e.g. building a library, or when we're doing a multi-file compilation, or when we're building a single file app.
The process begins by looking at the list of the root nodes and establishing their dependencies (dependent nodes). Once the dependencies are known, the compilation moves on to inspecting the dependencies of the dependencies, and so on, until all dependencies are known and marked within the dependency graph. When that happens, the compilation is done.
The expansion of the graph is required to stay within the limits of a compilation group. Compilation group is a component that controls how the dependency graph is expanded. The role of it is best illustrated by contrasting a multifile and single file compilation: in a single file compilation, all methods and types that are statically reachable from the roots become part of the dependency graph, irrespective of the input assembly that defines them. In a multi-file compilation, some of the compilation happens as part of a different unit of work: the methods and types that are not part of the current unit of work shouldn't have their dependencies examined and they should not be a part of the dependency graph.
The advantage of having the two abstractions (compilation roots, and a class that controls how the dependency graph is expanded) is that the core compilation process can be completely unaware of the specific compilation mode (e.g. whether we're building a library, or whether we're doing a multi-file compilation). The details are fully wrapped behind the two abstractions and give us a great expressive power for defining or experimenting with new compilation modes, while keeping all the logic in a single place. For example, we support a single method compilation mode where we compile only one method. This mode is useful for troubleshooting code generation. The compilation driver can define additional compilation modes (e.g. a mode that compiles a single type and all the associated methods) without having to change the compiler itself.
Related classes: `ICompilationRootProvider`, `CompilationModuleGroup`
### Dependency types
The dependency graph analysis can work with several kinds of dependencies between the nodes:
* **Static dependencies**: these are the most common. If node A is part of the dependency graph and it declares it requires node B, node B also becomes part of the dependency graph.
* **Conditional dependencies**: Node A declares that it depends on node B, but only if node C is part of the graph. If that's the case, node B will become part of the graph if both A and C are in the graph.
* **Dynamic dependencies**: These are quite expensive to have in the system, so we only use them rarely. They let the node inspect other nodes within the graph and inject nodes based on their presence. They are pretty much only used for analysis of generic virtual methods.
To show how the dependency graph looks like in real life let's look at an example of how an (optional) optimization within the compiler around virtual method usage tracking works:
```csharp
abstract class Foo
{
public abstract void VirtualMethod();
public virtual void UnusedVirtualMethod() { }
}
class Bar : Foo
{
public override void VirtualMethod() { }
public override void UnusedVirtualMethod() { }
}
class Baz : Foo
{
public override void VirtualMethod() { }
}
class Program
{
static int Main()
{
Foo f = new Bar();
f.VirtualMethod();
return f is Baz ? 0 : 100;
}
}
```
The dependency graph for the above program would look something like this:
![Dependency graph](../images/simple-dependency-graph.svg)
The rectangle-shaped nodes represent method bodies, the oval-shaped nodes represent types, the dashed rectangles represent virtual method use, and the dotted oval-shaped node is an unconstructed type.
The dashed edges are conditional dependencies, with the condition marked on the label.
* `Program::Main` creates a new instance of `Bar`. For that, it will allocate an object on the GC heap and call a constructor to initialize it. Therefore, it needs the data structure that represents the `Bar` type and `Bar`'s default constructor. The method then calls `VirtualMethod`. Even though from this simple example we know what specific method body this will end up calling (we can devirtualize the call in our head), we can't know in general, so we say `Program::Main` also depends on "Virtual method use of Foo::VirtualMethod". The last line of the program performs a type check. To do the type check, the generated code needs to reference a data structure that represents type `Baz`. The interesting thing about a type check is that we don't need to generate a full data structure describing the type, only enough to be able to tell if the cast succeeds. So we say `Program::Main` also depends on "unconstructed type data structure" for `Baz`.
* The data structure that represents type `Bar` has two important kinds of dependencies. It depends on its base type (`Foo`) - a pointer to it is required to make casting work - and it also contains the vtable. The entries in the vtable are conditional - if a virtual method is never called, we don't need to place it in the vtable. As a result of the situation in the graph, the method body for `Bar::VirtualMethod` is going to be part of the graph, but `Bar::UnusedVirtualMethod` will not, because it's conditioned on a node that is not present in the graph.
* The data structure that represents `Baz` is a bit different from `Bar`. We call this an "unconstructed type" structure. Unconstructed type structures don't contain a vtable, and therefore `Baz` is missing a virtual method use dependency for `Baz::VirtualMethod` conditioned on the use of `Foo::VirtualMethod`.
Notice how using conditional dependencies helped us avoid compiling method bodies for `Foo::UnusedVirtualMethod` and `Bar::UnusedVirtualMethod` because the virtual method is never used. We also avoided generating `Baz::VirtualMethod`, because `Baz` was never allocated within the program. We generated the data structure that represents `Baz`, but because the data structure was only generated for the purposes of casting, it doesn't have a vtable that would pull `Baz::VirtualMethod` into the dependency graph.
Note that while "constructed" and "unconstructed" type nodes are modelled separately in the dependency graph, at the object writing time they get coalesced into one. If the graph has a type in both the unconstructed and constructed form, only the constructed form will be emitted into the executable and places referring to the unconstructed form will be redirected to the constructed form, to maintain type identity.
Related compiler switches: `--dgmllog` serializes the dependency graph into an XML file. The XML file captures all the nodes in the graph, but only captures the first edge leading to the node (knowing the first edge is enough for most purposes). `--fulllog` generates an even bigger XML file that captures all the edges.
Related tools: [Dependency analysis viewer](../how-to-debug-compiler-dependency-analysis.md) is a tool that listens to ETW events generated by all the ILC compiler processes on the machine and lets you interactively explore the graph.
## Object writing
The final phase of compilation is writing out the outputs. The output of the compilation depends on the target environment but will typically be some sort of object file. An object file typically consists of blobs of code or data with links (or relocations) between them, and symbols: named locations within a blob. The relocations point to symbols, either defined within the same object file, or in a different module.
While the object file format is highly target specific, the compiler represents dependency nodes that have object data associated with them the same way irrespective of the target - with the `ObjectNode` class. `ObjectNode` class allows its children to specify the section where to place their data (code, read only data, uninitialized data, etc.), and crucially, the data itself (represented by the `ObjectData` class returned from `GetObjectData` method).
On a high level, the role of the object writer is to go over all the marked `ObjectNode`s in the graph, retrieve their data, defined symbols, and relocations to other symbols, and store them in the object file.
CoreRT compiler contains multiple object writers:
* Native object writer (`src/Native/ObjWriter`) based on LLVM that is capable of producing Windows PE, Linux ELF, and macOS Mach-O file formats
* Native object writer based on LLVM for WebAssembly
* CppWriter that generates textual C++ code describing the data structures
* Ready to run object writer that generates mixed CIL/native executables in the ready to run format for CoreCLR
Related command line arguments: `--map` produces a map of all the object nodes that were emitted into the object file.
## Optimization pluggability
An advantage of a fully ahead of time compiled environment is that the compiler can make closed world assumptions about the code being compiled. For example: lacking the ability to load arbitrary CIL at runtime (either through `Assembly.Load`, or `Reflection.Emit`), if the compiler sees that there's only one type implementing an interface, it can replace all the interface calls in the program with direct calls, and apply additional optimizations enabled by it, such as inlining. If the target environment allowed dynamic code, such optimization would be invalid.
The compiler is structured to allow such optimizations, but remains policy-free as to when the optimization should be applied. This allow both fully AOT compiled and mixed (JIT/interpreted) code execution strategies. The policies are always captured in an abstract class or an interface, the implementation of which is selected by the compilation driver and passed to the compilation builder. This allows a great degree of flexibility and gives a lot of power to influence the compilation from the compilation driver, without hardcoding the conditions when the optimization is applicable into the compiler.
An example of such policy is the virtual method table (vtable) generation policy. The compiler can build vtables two ways: lazily, or by reading the type's metadata and generating a vtable slot for every new virtual method present in the type's method list. The depenceny analysis example graph a couple sections above was describing how conditional dependencies can be used to track what vtable slots and virtual method bodies we need to generate for a program to work. This is an example of an optimization that requires closed world assumptions. The policy is captured in a `VTableSliceProvider` class and allows the driver to select the vtable generation policy per type. This allows the compilation driver a great degree of control to fine tune when the optimization is allowed to happen (e.g. even in the presence of a JIT, we could still allow this optimization to happen on types that are not visible/accessible from the non-AOT compiled parts of the program or through reflection).
The policies that can be configured in the driver span a wide range of areas: generation of reflection metadata, devirtualization, generation of vtables, generation of stack trace metadata for `Exception.ToString`, generation of debug information, the source of IL for method bodies, etc.
## IL scanning
Another component of ILC is the IL scanner. IL scanning is an optional step that can be executed before the compilation. In many ways, the IL scanning acts as another compilation with a null/dummy code generation backend. The IL scanner scans the IL of all the method bodies that become part of the dependency graph starting from the roots and expands their dependencies. The IL scanner ends up building the same dependency graph a code generation backend would, but the nodes in the graph that represent method bodies don't have any machine code instructions associated with them. This process is relatively fast since there's no code generation involved, but the resulting graph contains a lot of valuable insights into the compiled program. The dependency graph built by the IL scanner is a strict superset of the graph built by a real compilation since the IL scanner doesn't model optimizations such as inlining and devirtualization.
The results of the IL scanner are input into the subsequent compilation process. For example, the IL scanner can use the lazy vtable generation policy to build vtables with just the slots needed, and assign slot numbers to each slot in the vtable at the end of scanning. The vtable layouts computed lazily during scanning can then be used by the real compilation process to inline vtable lookups at the callsites. Inlining the vtable lookup at the callsite would not be possible with a lazy vtable generation policy because the exact slot assignments of lazy vtables aren't stable until the compilation is done.
The IL scanning process is optional and the compilation driver can skip it if compilation throughput is more important than runtime code quality.
Related classes: `ILScanner`
## Coupling with the base class libraries
The compiler has a certain level of coupling with the underlying base class library (the `System.Private.*` libraries within the repo). The coupling is twofold:
* Binary format of the generated data structures
* Expectations about the existence of certain methods within the core library
Examples of the binary formats generated by the compiler and used by the base class libraries would be the format of the data structure that represents a type at runtime (`EEType`), or the blob of bytes that describes non-essential information about the type (such as the type name, or a list of methods). These data structures form a contract and allow the managed code in the base class library to provide rich services to user code through library APIs at runtime (such as the reflection APIs). Generation of some of these data structures is optional, but for some it's mandatory because they're required to execute any managed code.
The compiler also needs to call into some well-known entrypoints within the base class library to support the generated code. The base class library needs to define these methods. Examples of such entrypoints would be various helpers to throw `OverflowException` during mathematical operations, `IndexOutOfRangeException` during array access, or various helpers to aid in generating p/invoke marshalling code (e.g. converting a UTF-16 string to ANSI and back before/after invoking the native method).
One interesting thing to point out is that the coupling of the compiler with the base class libraries is relatively loose (there are only few mandatory parts). This allows different base class libraries to be used with ILC. Such base class libraries could look quite different from what regular .NET developers are used to (e.g. a `System.Object` that doesn't have a `ToString` method) but could allow using type safe code in environments where regular .NET would be considered "too heavy". Various experiments with such lightweight code have been done in the past, and some of them even shipped as part of the Windows operating system.
Example of such alternative base class library is [Test.CoreLib](../../src/Test.CoreLib/). The `Test.CoreLib` library provides a very minimal API surface. This, coupled with the fact that it requires almost no initialization, makes it a great assistant in bringing CoreRT to new platforms.
## Compiler-generated method bodies
Besides compiling the code provided by the user in the form of input assemblies, the compiler also needs to compile various helpers generated within the compiler. The helpers are used to lower some of the higher-level .NET constructs into concepts that the underlying code generation backend understands. These helpers are emitted as IL code on the fly, without being physically backed by IL in an assembly on disk. Having the higher level concepts expressed as regular IL helps avoid having to implement the higher-level concept in each code generation backend (we only must do it once because IL is the thing all backends understand).
The helpers serve various purposes such as:
* Helpers to support invoking delegates
* Helpers that support marshalling parameters and return values for P/Invoke
* Helpers that support `ValueType.GetHashCode` and `ValueType.Equals`
* Helpers that support reflection: e.g. `Assembly.GetExecutingAssembly`
Related classes: `ILEmitter`, `ILStubMethod`
Related ILC command line switches: `--ildump` to dump all generated IL into a file and map debug information to it (allows source stepping through the generated IL at runtime).

Просмотреть файл

@ -27,7 +27,7 @@ You should now be able to use the `dotnet` commands of the CLI tools.
* Ensure that you have done a repo build per the instructions above.
* Create a new folder and switch into it.
* Run `dotnet new console` on the command/shell prompt. This will add a project template. If you get an error, please ensure the [pre-requisites](prerequisites-for-building.md) are installed.
* Modify `.csproj` file that is part of your project. A few lines at the top and at the bottom are different from the default template.
* Modify `.csproj` file that is part of your project. **Important:** A few lines at the top and at the bottom are different from the default template - don't miss updating them!
```
<Project>

Просмотреть файл

@ -0,0 +1,43 @@
digraph "SimpleDependencyGraph" {
ordering=out;
rankdir=LR;
node [shape=box];
Code_Program_Main[label="Program::Main"];
Code_Bar__ctor[label="Bar::.ctor"];
Code_Bar_VirtualMethod[label="Bar::VirtualMethod"];
Code_Bar_UnusedVirtualMethod[label="Bar::UnusedVirtualMethod"];
Code_Foo_UnusedVirtualMethod[label="Foo::UnusedVirtualMethod"];
Code_Foo__ctor[label="Foo::.ctor"];
Code_Object__ctor[label="Object::.ctor"];
node [shape=ellipse];
Type_Bar[label="Bar"];
Type_Foo[label="Foo"];
Type_Object[label="Object"];
node [shape=ellipse, style=dotted]
Type_Baz[label="Baz"]
node [shape=box, style=dashed];
Virtual_Foo_VirtualMethod[label="Foo::VirtualMethod"];
Code_Program_Main -> Code_Bar__ctor;
Code_Program_Main -> Type_Bar;
Code_Program_Main -> Virtual_Foo_VirtualMethod;
Code_Program_Main -> Type_Baz;
Type_Baz -> Type_Foo;
Type_Bar -> Type_Foo;
Type_Foo -> Type_Object;
Type_Bar -> Code_Bar_VirtualMethod[label="Foo::VirtualMethod is used", style=dashed];
Type_Bar -> Code_Bar_UnusedVirtualMethod[label="Foo::UnusedVirtualMethod is used", style=dashed];
Type_Foo -> Code_Foo_UnusedVirtualMethod[label="Foo::UnusedVirtualMethod is used", style=dashed];
Code_Bar__ctor -> Code_Foo__ctor;
Code_Foo__ctor -> Code_Object__ctor;
overlap=false;
fontsize=12;
}

Просмотреть файл

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: SimpleDependencyGraph Pages: 1 -->
<svg width="1067pt" height="236pt"
viewBox="0.00 0.00 1067.00 236.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 232)">
<title>SimpleDependencyGraph</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-232 1063,-232 1063,4 -4,4"/>
<!-- Code_Program_Main -->
<g id="node1" class="node"><title>Code_Program_Main</title>
<polygon fill="none" stroke="black" points="98,-109 0,-109 0,-73 98,-73 98,-109"/>
<text text-anchor="middle" x="49" y="-87.3" font-family="Times New Roman,serif" font-size="14.00">Program::Main</text>
</g>
<!-- Code_Bar__ctor -->
<g id="node2" class="node"><title>Code_Bar__ctor</title>
<polygon fill="none" stroke="black" points="232,-200 164,-200 164,-164 232,-164 232,-200"/>
<text text-anchor="middle" x="198" y="-178.3" font-family="Times New Roman,serif" font-size="14.00">Bar::.ctor</text>
</g>
<!-- Code_Program_Main&#45;&gt;Code_Bar__ctor -->
<g id="edge1" class="edge"><title>Code_Program_Main&#45;&gt;Code_Bar__ctor</title>
<path fill="none" stroke="black" d="M72.272,-109.083C88.9615,-122.169 112.672,-139.802 135,-153 141.259,-156.7 148.068,-160.288 154.807,-163.606"/>
<polygon fill="black" stroke="black" points="153.362,-166.794 163.894,-167.949 156.38,-160.479 153.362,-166.794"/>
</g>
<!-- Type_Bar -->
<g id="node8" class="node"><title>Type_Bar</title>
<ellipse fill="none" stroke="black" cx="198" cy="-126" rx="27" ry="18"/>
<text text-anchor="middle" x="198" y="-122.3" font-family="Times New Roman,serif" font-size="14.00">Bar</text>
</g>
<!-- Code_Program_Main&#45;&gt;Type_Bar -->
<g id="edge2" class="edge"><title>Code_Program_Main&#45;&gt;Type_Bar</title>
<path fill="none" stroke="black" d="M98.1333,-102.46C119.142,-107.462 143.303,-113.215 162.482,-117.781"/>
<polygon fill="black" stroke="black" points="161.753,-121.206 172.292,-120.117 163.375,-114.396 161.753,-121.206"/>
</g>
<!-- Type_Baz -->
<g id="node11" class="node"><title>Type_Baz</title>
<ellipse fill="none" stroke="black" stroke-dasharray="1,5" cx="198" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="198" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Baz</text>
</g>
<!-- Code_Program_Main&#45;&gt;Type_Baz -->
<g id="edge4" class="edge"><title>Code_Program_Main&#45;&gt;Type_Baz</title>
<path fill="none" stroke="black" d="M81.9536,-72.8704C97.7508,-64.1232 117.201,-53.6724 135,-45 144.736,-40.2562 155.506,-35.4252 165.301,-31.1859"/>
<polygon fill="black" stroke="black" points="166.877,-34.3185 174.696,-27.169 164.125,-27.8822 166.877,-34.3185"/>
</g>
<!-- Virtual_Foo_VirtualMethod -->
<g id="node12" class="node"><title>Virtual_Foo_VirtualMethod</title>
<polygon fill="none" stroke="black" stroke-dasharray="5,2" points="261,-90 135,-90 135,-54 261,-54 261,-90"/>
<text text-anchor="middle" x="198" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">Foo::VirtualMethod</text>
</g>
<!-- Code_Program_Main&#45;&gt;Virtual_Foo_VirtualMethod -->
<g id="edge3" class="edge"><title>Code_Program_Main&#45;&gt;Virtual_Foo_VirtualMethod</title>
<path fill="none" stroke="black" d="M98.1333,-84.7787C106.651,-83.6778 115.686,-82.51 124.697,-81.3453"/>
<polygon fill="black" stroke="black" points="125.363,-84.7884 134.832,-80.0353 124.466,-77.8461 125.363,-84.7884"/>
</g>
<!-- Code_Foo__ctor -->
<g id="node6" class="node"><title>Code_Foo__ctor</title>
<polygon fill="none" stroke="black" points="611.5,-228 539.5,-228 539.5,-192 611.5,-192 611.5,-228"/>
<text text-anchor="middle" x="575.5" y="-206.3" font-family="Times New Roman,serif" font-size="14.00">Foo::.ctor</text>
</g>
<!-- Code_Bar__ctor&#45;&gt;Code_Foo__ctor -->
<g id="edge11" class="edge"><title>Code_Bar__ctor&#45;&gt;Code_Foo__ctor</title>
<path fill="none" stroke="black" d="M232.323,-184.485C299.78,-189.515 452.571,-200.908 529.075,-206.613"/>
<polygon fill="black" stroke="black" points="529.114,-210.125 539.347,-207.379 529.635,-203.145 529.114,-210.125"/>
</g>
<!-- Code_Bar_VirtualMethod -->
<g id="node3" class="node"><title>Code_Bar_VirtualMethod</title>
<polygon fill="none" stroke="black" points="636.5,-120 514.5,-120 514.5,-84 636.5,-84 636.5,-120"/>
<text text-anchor="middle" x="575.5" y="-98.3" font-family="Times New Roman,serif" font-size="14.00">Bar::VirtualMethod</text>
</g>
<!-- Code_Bar_UnusedVirtualMethod -->
<g id="node4" class="node"><title>Code_Bar_UnusedVirtualMethod</title>
<polygon fill="none" stroke="black" points="658,-66 493,-66 493,-30 658,-30 658,-66"/>
<text text-anchor="middle" x="575.5" y="-44.3" font-family="Times New Roman,serif" font-size="14.00">Bar::UnusedVirtualMethod</text>
</g>
<!-- Code_Foo_UnusedVirtualMethod -->
<g id="node5" class="node"><title>Code_Foo_UnusedVirtualMethod</title>
<polygon fill="none" stroke="black" points="1059,-120 890,-120 890,-84 1059,-84 1059,-120"/>
<text text-anchor="middle" x="974.5" y="-98.3" font-family="Times New Roman,serif" font-size="14.00">Foo::UnusedVirtualMethod</text>
</g>
<!-- Code_Object__ctor -->
<g id="node7" class="node"><title>Code_Object__ctor</title>
<polygon fill="none" stroke="black" points="1017.5,-228 931.5,-228 931.5,-192 1017.5,-192 1017.5,-228"/>
<text text-anchor="middle" x="974.5" y="-206.3" font-family="Times New Roman,serif" font-size="14.00">Object::.ctor</text>
</g>
<!-- Code_Foo__ctor&#45;&gt;Code_Object__ctor -->
<g id="edge12" class="edge"><title>Code_Foo__ctor&#45;&gt;Code_Object__ctor</title>
<path fill="none" stroke="black" d="M611.731,-210C681.795,-210 838.931,-210 921.129,-210"/>
<polygon fill="black" stroke="black" points="921.252,-213.5 931.252,-210 921.252,-206.5 921.252,-213.5"/>
</g>
<!-- Type_Bar&#45;&gt;Code_Bar_VirtualMethod -->
<g id="edge8" class="edge"><title>Type_Bar&#45;&gt;Code_Bar_VirtualMethod</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M225.106,-124.331C282.243,-120.68 420.002,-111.875 504.47,-106.476"/>
<polygon fill="black" stroke="black" points="504.742,-109.966 514.498,-105.835 504.295,-102.98 504.742,-109.966"/>
<text text-anchor="middle" x="377" y="-123.8" font-family="Times New Roman,serif" font-size="14.00">Foo::VirtualMethod is used</text>
</g>
<!-- Type_Bar&#45;&gt;Code_Bar_UnusedVirtualMethod -->
<g id="edge9" class="edge"><title>Type_Bar&#45;&gt;Code_Bar_UnusedVirtualMethod</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M221.222,-116.66C233.094,-111.586 247.918,-105.114 261,-99 269.103,-95.2131 270.462,-92.6639 279,-90 345.518,-69.2474 423.688,-58.7081 482.916,-53.3784"/>
<polygon fill="black" stroke="black" points="483.338,-56.855 492.999,-52.5047 482.734,-49.8811 483.338,-56.855"/>
<text text-anchor="middle" x="377" y="-93.8" font-family="Times New Roman,serif" font-size="14.00">Foo::UnusedVirtualMethod is used</text>
</g>
<!-- Type_Foo -->
<g id="node9" class="node"><title>Type_Foo</title>
<ellipse fill="none" stroke="black" cx="575.5" cy="-156" rx="27" ry="18"/>
<text text-anchor="middle" x="575.5" y="-152.3" font-family="Times New Roman,serif" font-size="14.00">Foo</text>
</g>
<!-- Type_Bar&#45;&gt;Type_Foo -->
<g id="edge6" class="edge"><title>Type_Bar&#45;&gt;Type_Foo</title>
<path fill="none" stroke="black" d="M224.13,-130.77C239.844,-133.581 260.537,-136.974 279,-139 372.096,-149.214 482.409,-153.501 538.239,-155.123"/>
<polygon fill="black" stroke="black" points="538.242,-158.625 548.335,-155.405 538.437,-151.627 538.242,-158.625"/>
</g>
<!-- Type_Foo&#45;&gt;Code_Foo_UnusedVirtualMethod -->
<g id="edge10" class="edge"><title>Type_Foo&#45;&gt;Code_Foo_UnusedVirtualMethod</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M601.358,-150.741C621.434,-146.618 650.45,-140.937 676,-137 744.023,-126.518 821.223,-117.519 879.932,-111.272"/>
<polygon fill="black" stroke="black" points="880.354,-114.747 889.931,-110.216 879.618,-107.786 880.354,-114.747"/>
<text text-anchor="middle" x="774" y="-140.8" font-family="Times New Roman,serif" font-size="14.00">Foo::UnusedVirtualMethod is used</text>
</g>
<!-- Type_Object -->
<g id="node10" class="node"><title>Type_Object</title>
<ellipse fill="none" stroke="black" cx="974.5" cy="-156" rx="35.194" ry="18"/>
<text text-anchor="middle" x="974.5" y="-152.3" font-family="Times New Roman,serif" font-size="14.00">Object</text>
</g>
<!-- Type_Foo&#45;&gt;Type_Object -->
<g id="edge7" class="edge"><title>Type_Foo&#45;&gt;Type_Object</title>
<path fill="none" stroke="black" d="M602.548,-156C669.133,-156 846.153,-156 929.253,-156"/>
<polygon fill="black" stroke="black" points="929.384,-159.5 939.384,-156 929.384,-152.5 929.384,-159.5"/>
</g>
<!-- Type_Baz&#45;&gt;Type_Foo -->
<g id="edge5" class="edge"><title>Type_Baz&#45;&gt;Type_Foo</title>
<path fill="none" stroke="black" d="M224.132,-12.4854C277.675,-2.33781 403.894,12.8265 475,-51 501.476,-74.7654 469.041,-102.699 493,-129 504.61,-141.745 522.366,-148.485 538.344,-152.044"/>
<polygon fill="black" stroke="black" points="538.03,-155.547 548.505,-153.955 539.324,-148.667 538.03,-155.547"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 9.1 KiB

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse

Просмотреть файл

@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ vivid main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ vivid main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ vivid-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ vivid-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ vivid-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ vivid-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ vivid-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ vivid-security main restricted universe multiverse

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ wily main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ wily main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ wily-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ wily-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ wily-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ wily-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ wily-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ wily-security main restricted universe multiverse

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse

Просмотреть файл

@ -0,0 +1,11 @@
deb http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse

Просмотреть файл

@ -4,7 +4,7 @@ usage()
{
echo "Usage: $0 [BuildArch] [LinuxCodeName] [lldbx.y] [--skipunmount]"
echo "BuildArch can be: arm(default), armel, arm64, x86"
echo "LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial, zesty, alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
echo "LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial, zesty, bionic, alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
echo "lldbx.y - optional, LLDB version, can be: lldb3.6(default), lldb3.8, lldb3.9, lldb4.0, no-lldb. Ignored for alpine"
echo "--skipunmount - optional, will skip the unmount of rootfs folder."
exit 1
@ -118,6 +118,11 @@ for i in "$@" ; do
__LinuxCodeName=zesty
fi
;;
bionic)
if [ "$__LinuxCodeName" != "jessie" ]; then
__LinuxCodeName=bionic
fi
;;
jessie)
__LinuxCodeName=jessie
__UbuntuRepo="http://ftp.debian.org/debian/"

Просмотреть файл

@ -0,0 +1,11 @@
deb http://archive.ubuntu.com/ubuntu/ bionic main restricted universe
deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe
deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe
deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe
deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
deb-src http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
deb http://archive.ubuntu.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ bionic-security main restricted universe multiverse

Просмотреть файл

@ -1,6 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RyuJITVersion>3.0.0-preview1-26831-01</RyuJITVersion>
<RyuJITVersion>3.0.0-preview1-27005-01</RyuJITVersion>
<ObjectWriterVersion>1.0.0-alpha-26412-0</ObjectWriterVersion>
<CoreFxVersion>4.6.0-preview1-26831-01</CoreFxVersion>
<CoreFxUapVersion>4.7.0-preview1-26831-01</CoreFxUapVersion>

Просмотреть файл

@ -2,9 +2,6 @@
// 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.Runtime.CompilerServices;
namespace Internal.TypeSystem
{
// Additional members of MethodDesc related to code generation.
@ -48,6 +45,29 @@ namespace Internal.TypeSystem
}
}
/// <summary>
/// Gets a value specifying whether this method contains hot code and should
/// be aggressively optimized if possible.
/// </summary>
public virtual bool IsAggressiveOptimization
{
get
{
return false;
}
}
/// <summary>
/// Gets a value specifying whether this method should not be optimized.
/// </summary>
public virtual bool IsNoOptimization
{
get
{
return false;
}
}
/// <summary>
/// Gets a value specifying whether the implementation of this method
/// is provided by the runtime (i.e., through generated IL).
@ -128,6 +148,22 @@ namespace Internal.TypeSystem
}
}
public override bool IsAggressiveOptimization
{
get
{
return _methodDef.IsAggressiveOptimization;
}
}
public override bool IsNoOptimization
{
get
{
return _methodDef.IsNoOptimization;
}
}
public override bool IsAggressiveInlining
{
get
@ -188,6 +224,22 @@ namespace Internal.TypeSystem
}
}
public override bool IsAggressiveOptimization
{
get
{
return _typicalMethodDef.IsAggressiveOptimization;
}
}
public override bool IsNoOptimization
{
get
{
return _typicalMethodDef.IsNoOptimization;
}
}
public override bool IsAggressiveInlining
{
get

Просмотреть файл

@ -2,15 +2,11 @@
// 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;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Reflection.Metadata;
using System.Threading;
using System.Collections.Generic;
using Internal.TypeSystem;
namespace Internal.TypeSystem.Ecma
{
@ -28,6 +24,8 @@ namespace Internal.TypeSystem.Ecma
public const int RuntimeImplemented = 0x0080;
public const int InternalCall = 0x0100;
public const int Synchronized = 0x0200;
public const int AggressiveOptimization = 0x0400;
public const int NoOptimization = 0x0800;
public const int AttributeMetadataCache = 0x1000;
public const int Intrinsic = 0x2000;
@ -148,6 +146,15 @@ namespace Internal.TypeSystem.Ecma
if ((methodImplAttributes & MethodImplAttributes.NoInlining) != 0)
flags |= MethodFlags.NoInlining;
// System.Reflection.Primitives we build against doesn't define AggressiveOptimization
const MethodImplAttributes MethodImplAttributes_AggressiveOptimization = (MethodImplAttributes)0x0200;
// No optimization bit beats aggressive optimization bit (CLR compatible behavior)
if ((methodImplAttributes & MethodImplAttributes.NoOptimization) != 0)
flags |= MethodFlags.NoOptimization;
else if ((methodImplAttributes & MethodImplAttributes_AggressiveOptimization) != 0)
flags |= MethodFlags.AggressiveOptimization;
if ((methodImplAttributes & MethodImplAttributes.AggressiveInlining) != 0)
flags |= MethodFlags.AggressiveInlining;
@ -259,6 +266,22 @@ namespace Internal.TypeSystem.Ecma
}
}
public override bool IsAggressiveOptimization
{
get
{
return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveOptimization) & MethodFlags.AggressiveOptimization) != 0;
}
}
public override bool IsNoOptimization
{
get
{
return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoOptimization) & MethodFlags.NoOptimization) != 0;
}
}
public override bool IsAggressiveInlining
{
get

Просмотреть файл

@ -13,7 +13,7 @@ using Internal.NativeFormat;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a map between reflection metadata and generated method bodies.
/// Represents a map of generic virtual method implementations.
/// </summary>
internal sealed class GenericVirtualMethodTableNode : ObjectNode, ISymbolDefinitionNode
{

Просмотреть файл

@ -619,27 +619,9 @@ namespace Internal.IL
if (instParam != null)
{
_dependencies.Add(instParam, reason);
}
if (!referencingArrayAddressMethod)
{
_dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason);
}
else
{
// We don't want array Address method to be modeled in the generic dependency analysis.
// The method doesn't actually have runtime determined dependencies (won't do
// any generic lookups).
_dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason);
}
}
else if (targetMethod.AcquiresInstMethodTableFromThis())
{
_dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason);
}
else
{
_dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason);
}
_dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason);
}
}
else if (method.HasInstantiation)

Просмотреть файл

@ -1639,6 +1639,16 @@ namespace Internal.IL
}
var pointerSize = _compilation.NodeFactory.Target.PointerSize;
LLVMValueRef fn;
if (opcode == ILOpcode.calli)
{
fn = calliTarget;
}
else
{
fn = LLVMFunctionForMethod(callee, signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt, constrainedType);
}
LLVMValueRef returnAddress;
LLVMValueRef castReturnAddress = default;
TypeDesc returnType = signature.ReturnType;
@ -1711,15 +1721,6 @@ namespace Internal.IL
}
}
LLVMValueRef fn;
if (opcode == ILOpcode.calli)
{
fn = calliTarget;
}
else
{
fn = LLVMFunctionForMethod(callee, signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt, constrainedType);
}
LLVMValueRef llvmReturn = LLVM.BuildCall(_builder, fn, llvmArgs.ToArray(), string.Empty);
@ -2980,7 +2981,7 @@ namespace Internal.IL
private LLVMValueRef GetElementAddress(LLVMValueRef elementPosition, LLVMValueRef arrayReference, TypeDesc arrayElementType)
{
var elementSize = arrayElementType.IsValueType ? ((DefType)arrayElementType).InstanceByteCount : arrayElementType.GetElementSize();
var elementSize = arrayElementType.GetElementSize();
LLVMValueRef elementOffset = LLVM.BuildMul(_builder, elementPosition, BuildConstInt32(elementSize.AsInt), "elementOffset");
LLVMValueRef arrayOffset = LLVM.BuildAdd(_builder, elementOffset, ArrayBaseSize(), "arrayOffset");
return LLVM.BuildGEP(_builder, arrayReference, new LLVMValueRef[] { arrayOffset }, "elementPointer");

Просмотреть файл

@ -18,7 +18,7 @@ namespace Internal.JitInterface
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate void __getMethodSig(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
[return: MarshalAs(UnmanagedType.I1)]delegate bool __getMethodInfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_METHOD_INFO info);
[return: MarshalAs(UnmanagedType.I1)]delegate bool __getMethodInfo(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CorInfoInline __canInline(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint pRestrictions);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
@ -172,7 +172,7 @@ namespace Internal.JitInterface
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CORINFO_CLASS_STRUCT_* __getParentType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CorInfoType __getChildType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, ref CORINFO_CLASS_STRUCT_* clsRet);
delegate CorInfoType __getChildType(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
[return: MarshalAs(UnmanagedType.Bool)]delegate bool __satisfiesClassConstraints(IntPtr _this, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
@ -188,13 +188,13 @@ namespace Internal.JitInterface
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CORINFO_CLASS_STRUCT_* __getFieldClass(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CorInfoType __getFieldType(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref CORINFO_CLASS_STRUCT_* structType, CORINFO_CLASS_STRUCT_* memberParent);
delegate CorInfoType __getFieldType(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate uint __getFieldOffset(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
[return: MarshalAs(UnmanagedType.I1)]delegate bool __isWriteBarrierHelperRequired(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate void __getFieldInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, ref CORINFO_FIELD_INFO pResult);
delegate void __getFieldInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
[return: MarshalAs(UnmanagedType.I1)]delegate bool __isFieldStatic(IntPtr _this, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
@ -212,7 +212,7 @@ namespace Internal.JitInterface
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CORINFO_ARG_LIST_STRUCT_* __getArgNext(IntPtr _this, IntPtr* ppException, CORINFO_ARG_LIST_STRUCT_* args);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CorInfoTypeWithMod __getArgType(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, ref CORINFO_CLASS_STRUCT_* vcTypeRet);
delegate CorInfoTypeWithMod __getArgType(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate CORINFO_CLASS_STRUCT_* __getArgClass(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
@ -290,7 +290,7 @@ namespace Internal.JitInterface
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate void __GetProfilingHandle(IntPtr _this, IntPtr* ppException, [MarshalAs(UnmanagedType.Bool)] ref bool pbHookFunction, ref void* pProfilerHandle, [MarshalAs(UnmanagedType.Bool)] ref bool pbIndirectedHandles);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
delegate void __getCallInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, ref CORINFO_CALL_INFO pResult);
delegate void __getCallInfo(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
[return: MarshalAs(UnmanagedType.Bool)]delegate bool __canAccessFamily(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType);
[UnmanagedFunctionPointerAttribute(default(CallingConvention))]
@ -400,12 +400,12 @@ namespace Internal.JitInterface
}
}
[return: MarshalAs(UnmanagedType.I1)]static bool _getMethodInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_METHOD_INFO info)
[return: MarshalAs(UnmanagedType.I1)]static bool _getMethodInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info)
{
var _this = GetThis(thisHandle);
try
{
return _this.getMethodInfo(ftn, ref info);
return _this.getMethodInfo(ftn, info);
}
catch (Exception ex)
{
@ -1463,12 +1463,12 @@ namespace Internal.JitInterface
}
}
static CorInfoType _getChildType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, ref CORINFO_CLASS_STRUCT_* clsRet)
static CorInfoType _getChildType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet)
{
var _this = GetThis(thisHandle);
try
{
return _this.getChildType(clsHnd, ref clsRet);
return _this.getChildType(clsHnd, clsRet);
}
catch (Exception ex)
{
@ -1575,12 +1575,12 @@ namespace Internal.JitInterface
}
}
static CorInfoType _getFieldType(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, ref CORINFO_CLASS_STRUCT_* structType, CORINFO_CLASS_STRUCT_* memberParent)
static CorInfoType _getFieldType(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent)
{
var _this = GetThis(thisHandle);
try
{
return _this.getFieldType(field, ref structType, memberParent);
return _this.getFieldType(field, structType, memberParent);
}
catch (Exception ex)
{
@ -1617,12 +1617,12 @@ namespace Internal.JitInterface
}
}
static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, ref CORINFO_FIELD_INFO pResult)
static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult)
{
var _this = GetThis(thisHandle);
try
{
_this.getFieldInfo(ref pResolvedToken, callerHandle, flags, ref pResult);
_this.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult);
}
catch (Exception ex)
{
@ -1737,12 +1737,12 @@ namespace Internal.JitInterface
}
}
static CorInfoTypeWithMod _getArgType(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, ref CORINFO_CLASS_STRUCT_* vcTypeRet)
static CorInfoTypeWithMod _getArgType(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet)
{
var _this = GetThis(thisHandle);
try
{
return _this.getArgType(sig, args, ref vcTypeRet);
return _this.getArgType(sig, args, vcTypeRet);
}
catch (Exception ex)
{
@ -2274,12 +2274,12 @@ namespace Internal.JitInterface
}
}
static void _getCallInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, ref CORINFO_CALL_INFO pResult)
static void _getCallInfo(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult)
{
var _this = GetThis(thisHandle);
try
{
_this.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, ref pResult);
_this.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult);
}
catch (Exception ex)
{

Просмотреть файл

@ -156,7 +156,7 @@ namespace Internal.JitInterface
_isFallbackBodyCompilation = methodIL != null;
CORINFO_METHOD_INFO methodInfo;
methodIL = Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, out methodInfo);
methodIL = Get_CORINFO_METHOD_INFO(MethodBeingCompiled, methodIL, &methodInfo);
// This is e.g. an "extern" method in C# without a DllImport or InternalCall.
if (methodIL == null)
@ -538,7 +538,7 @@ namespace Internal.JitInterface
private FieldDesc HandleToObject(CORINFO_FIELD_STRUCT_* field) { return (FieldDesc)HandleToObject((IntPtr)field); }
private CORINFO_FIELD_STRUCT_* ObjectToHandle(FieldDesc field) { return (CORINFO_FIELD_STRUCT_*)ObjectToHandle((Object)field); }
private MethodIL Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, out CORINFO_METHOD_INFO methodInfo)
private MethodIL Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORINFO_METHOD_INFO* methodInfo)
{
// MethodIL can be provided externally for the case of a method whose IL was replaced because we couldn't compile it.
if (methodIL == null)
@ -546,29 +546,29 @@ namespace Internal.JitInterface
if (methodIL == null)
{
methodInfo = default(CORINFO_METHOD_INFO);
*methodInfo = default(CORINFO_METHOD_INFO);
return null;
}
methodInfo.ftn = ObjectToHandle(method);
methodInfo.scope = (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL);
methodInfo->ftn = ObjectToHandle(method);
methodInfo->scope = (CORINFO_MODULE_STRUCT_*)ObjectToHandle(methodIL);
var ilCode = methodIL.GetILBytes();
methodInfo.ILCode = (byte*)GetPin(ilCode);
methodInfo.ILCodeSize = (uint)ilCode.Length;
methodInfo.maxStack = (uint)methodIL.MaxStack;
methodInfo.EHcount = (uint)methodIL.GetExceptionRegions().Length;
methodInfo.options = methodIL.IsInitLocals ? CorInfoOptions.CORINFO_OPT_INIT_LOCALS : (CorInfoOptions)0;
methodInfo.regionKind = CorInfoRegionKind.CORINFO_REGION_NONE;
methodInfo->ILCode = (byte*)GetPin(ilCode);
methodInfo->ILCodeSize = (uint)ilCode.Length;
methodInfo->maxStack = (uint)methodIL.MaxStack;
methodInfo->EHcount = (uint)methodIL.GetExceptionRegions().Length;
methodInfo->options = methodIL.IsInitLocals ? CorInfoOptions.CORINFO_OPT_INIT_LOCALS : (CorInfoOptions)0;
methodInfo->regionKind = CorInfoRegionKind.CORINFO_REGION_NONE;
Get_CORINFO_SIG_INFO(method, out methodInfo.args);
Get_CORINFO_SIG_INFO(methodIL.GetLocals(), out methodInfo.locals);
Get_CORINFO_SIG_INFO(method, &methodInfo->args);
Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals);
return methodIL;
}
private void Get_CORINFO_SIG_INFO(MethodDesc method, out CORINFO_SIG_INFO sig, bool isFatFunctionPointer = false)
private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool isFatFunctionPointer = false)
{
Get_CORINFO_SIG_INFO(method.Signature, out sig);
Get_CORINFO_SIG_INFO(method.Signature, sig);
// Does the method have a hidden parameter?
bool hasHiddenParameter = method.RequiresInstArg() && !isFatFunctionPointer;
@ -585,76 +585,76 @@ namespace Internal.JitInterface
// We only populate sigInst for intrinsic methods because most of the time,
// JIT doesn't care what the instantiation is and this is expensive.
Instantiation owningTypeInst = method.OwningType.Instantiation;
sig.sigInst.classInstCount = (uint)owningTypeInst.Length;
sig->sigInst.classInstCount = (uint)owningTypeInst.Length;
if (owningTypeInst.Length > 0)
{
var classInst = new IntPtr[owningTypeInst.Length];
for (int i = 0; i < owningTypeInst.Length; i++)
classInst[i] = (IntPtr)ObjectToHandle(owningTypeInst[i]);
sig.sigInst.classInst = (CORINFO_CLASS_STRUCT_**)GetPin(classInst);
sig->sigInst.classInst = (CORINFO_CLASS_STRUCT_**)GetPin(classInst);
}
}
if (hasHiddenParameter)
{
sig.callConv |= CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE;
sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_PARAMTYPE;
}
}
private void Get_CORINFO_SIG_INFO(MethodSignature signature, out CORINFO_SIG_INFO sig)
private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig)
{
sig.callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask);
sig->callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask);
// Varargs are not supported in .NET Core
if (sig.callConv == CorInfoCallConv.CORINFO_CALLCONV_VARARG)
if (sig->callConv == CorInfoCallConv.CORINFO_CALLCONV_VARARG)
ThrowHelper.ThrowBadImageFormatException();
if (!signature.IsStatic) sig.callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS;
if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS;
TypeDesc returnType = signature.ReturnType;
CorInfoType corInfoRetType = asCorInfoType(signature.ReturnType, out sig.retTypeClass);
sig._retType = (byte)corInfoRetType;
sig.retTypeSigClass = sig.retTypeClass; // The difference between the two is not relevant for ILCompiler
CorInfoType corInfoRetType = asCorInfoType(signature.ReturnType, &sig->retTypeClass);
sig->_retType = (byte)corInfoRetType;
sig->retTypeSigClass = sig->retTypeClass; // The difference between the two is not relevant for ILCompiler
sig.flags = 0; // used by IL stubs code
sig->flags = 0; // used by IL stubs code
sig.numArgs = (ushort)signature.Length;
sig->numArgs = (ushort)signature.Length;
sig.args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index
sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index
sig.sigInst.classInst = null; // Not used by the JIT
sig.sigInst.classInstCount = 0; // Not used by the JIT
sig.sigInst.methInst = null; // Not used by the JIT
sig.sigInst.methInstCount = (uint)signature.GenericParameterCount;
sig->sigInst.classInst = null; // Not used by the JIT
sig->sigInst.classInstCount = 0; // Not used by the JIT
sig->sigInst.methInst = null; // Not used by the JIT
sig->sigInst.methInstCount = (uint)signature.GenericParameterCount;
sig.pSig = (byte*)ObjectToHandle(signature);
sig.cbSig = 0; // Not used by the JIT
sig.scope = null; // Not used by the JIT
sig.token = 0; // Not used by the JIT
sig->pSig = (byte*)ObjectToHandle(signature);
sig->cbSig = 0; // Not used by the JIT
sig->scope = null; // Not used by the JIT
sig->token = 0; // Not used by the JIT
}
private void Get_CORINFO_SIG_INFO(LocalVariableDefinition[] locals, out CORINFO_SIG_INFO sig)
private void Get_CORINFO_SIG_INFO(LocalVariableDefinition[] locals, CORINFO_SIG_INFO* sig)
{
sig.callConv = CorInfoCallConv.CORINFO_CALLCONV_DEFAULT;
sig._retType = (byte)CorInfoType.CORINFO_TYPE_VOID;
sig.retTypeClass = null;
sig.retTypeSigClass = null;
sig.flags = (byte)CorInfoSigInfoFlags.CORINFO_SIGFLAG_IS_LOCAL_SIG;
sig->callConv = CorInfoCallConv.CORINFO_CALLCONV_DEFAULT;
sig->_retType = (byte)CorInfoType.CORINFO_TYPE_VOID;
sig->retTypeClass = null;
sig->retTypeSigClass = null;
sig->flags = (byte)CorInfoSigInfoFlags.CORINFO_SIGFLAG_IS_LOCAL_SIG;
sig.numArgs = (ushort)locals.Length;
sig->numArgs = (ushort)locals.Length;
sig.sigInst.classInst = null;
sig.sigInst.classInstCount = 0;
sig.sigInst.methInst = null;
sig.sigInst.methInstCount = 0;
sig->sigInst.classInst = null;
sig->sigInst.classInstCount = 0;
sig->sigInst.methInst = null;
sig->sigInst.methInstCount = 0;
sig.args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index
sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index
sig.pSig = (byte*)ObjectToHandle(locals);
sig.cbSig = 0; // Not used by the JIT
sig.scope = null; // Not used by the JIT
sig.token = 0; // Not used by the JIT
sig->pSig = (byte*)ObjectToHandle(locals);
sig->cbSig = 0; // Not used by the JIT
sig->scope = null; // Not used by the JIT
sig->token = 0; // Not used by the JIT
}
private CorInfoType asCorInfoType(TypeDesc type)
@ -690,10 +690,10 @@ namespace Internal.JitInterface
return CorInfoType.CORINFO_TYPE_CLASS;
}
private CorInfoType asCorInfoType(TypeDesc type, out CORINFO_CLASS_STRUCT_* structType)
private CorInfoType asCorInfoType(TypeDesc type, CORINFO_CLASS_STRUCT_** structType)
{
var corInfoType = asCorInfoType(type);
structType = ((corInfoType == CorInfoType.CORINFO_TYPE_CLASS) ||
*structType = ((corInfoType == CorInfoType.CORINFO_TYPE_CLASS) ||
(corInfoType == CorInfoType.CORINFO_TYPE_VALUECLASS) ||
(corInfoType == CorInfoType.CORINFO_TYPE_BYREF)) ? ObjectToHandle(type) : null;
return corInfoType;
@ -774,6 +774,11 @@ namespace Internal.JitInterface
result |= CorInfoFlag.CORINFO_FLG_DONT_INLINE;
}
if (method.IsAggressiveOptimization)
{
result |= CorInfoFlag.CORINFO_FLG_AGGRESSIVE_OPT;
}
// TODO: Cache inlining hits
// Check for an inlining directive.
@ -817,12 +822,12 @@ namespace Internal.JitInterface
{
MethodDesc method = HandleToObject(ftn);
Get_CORINFO_SIG_INFO(method, out *sig);
Get_CORINFO_SIG_INFO(method, sig);
}
private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_METHOD_INFO info)
private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info)
{
MethodIL methodIL = Get_CORINFO_METHOD_INFO(HandleToObject(ftn), null, out info);
MethodIL methodIL = Get_CORINFO_METHOD_INFO(HandleToObject(ftn), null, info);
return methodIL != null;
}
@ -1217,13 +1222,13 @@ namespace Internal.JitInterface
private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig)
{
var methodIL = (MethodIL)HandleToObject((IntPtr)module);
Get_CORINFO_SIG_INFO((MethodSignature)methodIL.GetObject((int)sigTOK), out *sig);
Get_CORINFO_SIG_INFO((MethodSignature)methodIL.GetObject((int)sigTOK), sig);
}
private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig)
{
var methodIL = (MethodIL)HandleToObject((IntPtr)module);
Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), out *sig);
Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig);
}
private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
@ -1988,7 +1993,7 @@ namespace Internal.JitInterface
private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getParentType"); }
private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, ref CORINFO_CLASS_STRUCT_* clsRet)
private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet)
{
CorInfoType result = CorInfoType.CORINFO_TYPE_UNDEF;
@ -1996,7 +2001,7 @@ namespace Internal.JitInterface
if (td.IsArray || td.IsByRef)
{
TypeDesc returnType = ((ParameterizedType)td).ParameterType;
result = asCorInfoType(returnType, out clsRet);
result = asCorInfoType(returnType, clsRet);
}
else
clsRet = null;
@ -2061,17 +2066,26 @@ namespace Internal.JitInterface
return ObjectToHandle(fieldDesc.OwningType);
}
private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, ref CORINFO_CLASS_STRUCT_* structType, CORINFO_CLASS_STRUCT_* memberParent)
private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* memberParent)
{
FieldDesc fieldDesc = HandleToObject(field);
TypeDesc fieldType = fieldDesc.FieldType;
CorInfoType type = asCorInfoType(fieldType, out structType);
CorInfoType type;
if (structType != null)
{
type = asCorInfoType(fieldType, structType);
}
else
{
type = asCorInfoType(fieldType);
}
Debug.Assert(!fieldDesc.OwningType.IsByReferenceOfT ||
fieldDesc.OwningType.GetKnownField("_value").FieldType.Category == TypeFlags.IntPtr);
if (type == CorInfoType.CORINFO_TYPE_NATIVEINT && fieldDesc.OwningType.IsByReferenceOfT)
{
Debug.Assert(structType == null);
Debug.Assert(structType == null || *structType == null);
Debug.Assert(fieldDesc.Offset.AsInt == 0);
type = CorInfoType.CORINFO_TYPE_BYREF;
}
@ -2091,13 +2105,12 @@ namespace Internal.JitInterface
private bool isWriteBarrierHelperRequired(CORINFO_FIELD_STRUCT_* field)
{ throw new NotImplementedException("isWriteBarrierHelperRequired"); }
private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, ref CORINFO_FIELD_INFO pResult)
private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult)
{
#if DEBUG
// In debug, write some bogus data to the struct to ensure we have filled everything
// properly.
fixed (CORINFO_FIELD_INFO* tmp = &pResult)
MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf<CORINFO_FIELD_INFO>());
MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf<CORINFO_FIELD_INFO>());
#endif
Debug.Assert(((int)flags & ((int)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_GET |
@ -2132,7 +2145,7 @@ namespace Internal.JitInterface
// The JIT wants to know how to access a static field on a generic type. We need a runtime lookup.
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_READYTORUN_HELPER;
pResult.helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE;
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE;
// Don't try to compute the runtime lookup if we're inlining. The JIT is going to abort the inlining
// attempt anyway.
@ -2171,14 +2184,14 @@ namespace Internal.JitInterface
helperId, runtimeDeterminedField.OwningType, contextMethod);
}
pResult.fieldLookup = CreateConstLookupToSymbol(helper);
pResult->fieldLookup = CreateConstLookupToSymbol(helper);
}
}
else
{
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
pResult.helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_STATIC_BASE;
ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid;
if (field.IsThreadStatic)
@ -2206,7 +2219,7 @@ namespace Internal.JitInterface
if (helperId != ReadyToRunHelperId.Invalid)
{
pResult.fieldLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType));
pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ReadyToRunHelper(helperId, field.OwningType));
}
}
}
@ -2218,15 +2231,15 @@ namespace Internal.JitInterface
if (field.IsInitOnly)
fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_FINAL;
pResult.fieldAccessor = fieldAccessor;
pResult.fieldFlags = fieldFlags;
pResult.fieldType = getFieldType(pResolvedToken.hField, ref pResult.structType, pResolvedToken.hClass);
pResult.accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
pResult->fieldAccessor = fieldAccessor;
pResult->fieldFlags = fieldFlags;
pResult->fieldType = getFieldType(pResolvedToken.hField, &pResult->structType, pResolvedToken.hClass);
pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
if (!field.IsStatic || !field.HasRva)
pResult.offset = (uint)field.Offset.AsInt;
pResult->offset = (uint)field.Offset.AsInt;
else
pResult.offset = 0xBAADF00D;
pResult->offset = 0xBAADF00D;
// TODO: We need to implement access checks for fields and methods. See JitInterface.cpp in mrtjit
// and STS::AccessCheck::CanAccess.
@ -2427,7 +2440,7 @@ namespace Internal.JitInterface
return (CORINFO_ARG_LIST_STRUCT_*)((int)args + 1);
}
private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, ref CORINFO_CLASS_STRUCT_* vcTypeRet)
private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet)
{
int index = (int)args;
Object sigObj = HandleToObject((IntPtr)sig->pSig);
@ -2438,7 +2451,7 @@ namespace Internal.JitInterface
{
TypeDesc type = methodSig[index];
CorInfoType corInfoType = asCorInfoType(type, out vcTypeRet);
CorInfoType corInfoType = asCorInfoType(type, vcTypeRet);
return (CorInfoTypeWithMod)corInfoType;
}
else
@ -2446,7 +2459,7 @@ namespace Internal.JitInterface
LocalVariableDefinition[] locals = (LocalVariableDefinition[])sigObj;
TypeDesc type = locals[index].Type;
CorInfoType corInfoType = asCorInfoType(type, out vcTypeRet);
CorInfoType corInfoType = asCorInfoType(type, vcTypeRet);
return (CorInfoTypeWithMod)corInfoType | (locals[index].IsPinned ? CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED : 0);
}
@ -3034,13 +3047,12 @@ namespace Internal.JitInterface
return constLookup;
}
private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, ref CORINFO_CALL_INFO pResult)
private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult)
{
#if DEBUG
// In debug, write some bogus data to the struct to ensure we have filled everything
// properly.
fixed (CORINFO_CALL_INFO* tmp = &pResult)
MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf<CORINFO_CALL_INFO>());
MemoryHelper.FillMemory((byte*)pResult, 0xcc, Marshal.SizeOf<CORINFO_CALL_INFO>());
#endif
MethodDesc method = HandleToObject(pResolvedToken.hMethod);
@ -3075,7 +3087,7 @@ namespace Internal.JitInterface
MethodDesc methodAfterConstraintResolution = method;
if (constrainedType == null)
{
pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
pResult->thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
}
else
{
@ -3104,17 +3116,17 @@ namespace Internal.JitInterface
Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface);
resolvedConstraint = true;
pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
pResult->thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
exactType = constrainedType;
}
else if (constrainedType.IsValueType)
{
pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_BOX_THIS;
pResult->thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_BOX_THIS;
}
else
{
pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_DEREF_THIS;
pResult->thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_DEREF_THIS;
}
}
@ -3127,13 +3139,13 @@ namespace Internal.JitInterface
if (targetMethod.HasInstantiation)
{
pResult.contextHandle = contextFromMethod(targetMethod);
pResult.exactContextNeedsRuntimeLookup = targetMethod.IsSharedByGenericInstantiations;
pResult->contextHandle = contextFromMethod(targetMethod);
pResult->exactContextNeedsRuntimeLookup = targetMethod.IsSharedByGenericInstantiations;
}
else
{
pResult.contextHandle = contextFromType(exactType);
pResult.exactContextNeedsRuntimeLookup = exactType.IsCanonicalSubtype(CanonicalFormKind.Any);
pResult->contextHandle = contextFromType(exactType);
pResult->exactContextNeedsRuntimeLookup = exactType.IsCanonicalSubtype(CanonicalFormKind.Any);
}
//
@ -3166,7 +3178,7 @@ namespace Internal.JitInterface
}
}
pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = false;
pResult->codePointerOrStubLookup.lookupKind.needsRuntimeLookup = false;
bool allowInstParam = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ALLOWINSTPARAM) != 0;
@ -3179,27 +3191,27 @@ namespace Internal.JitInterface
// JIT won't expect fat function pointers unless this is e.g. delegate creation
Debug.Assert((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0);
pResult.kind = CORINFO_CALL_KIND.CORINFO_CALL_CODE_POINTER;
pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL_CODE_POINTER;
if (pResult.exactContextNeedsRuntimeLookup)
if (pResult->exactContextNeedsRuntimeLookup)
{
pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true;
pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = 0;
pResult.codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER;
pResult->codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true;
pResult->codePointerOrStubLookup.lookupKind.runtimeLookupFlags = 0;
pResult->codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER;
// Do not bother computing the runtime lookup if we are inlining. The JIT is going
// to abort the inlining attempt anyway.
MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext);
if (contextMethod == MethodBeingCompiled)
{
pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod);
pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodEntry;
pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken));
pResult->codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod);
pResult->codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodEntry;
pResult->codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken));
}
}
else
{
pResult.codePointerOrStubLookup.constLookup =
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.FatFunctionPointer(targetMethod));
}
}
@ -3224,15 +3236,15 @@ namespace Internal.JitInterface
MethodDesc concreteMethod = targetMethod;
targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
pResult.kind = CORINFO_CALL_KIND.CORINFO_CALL;
pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL;
if (targetMethod.IsConstructor && targetMethod.OwningType.IsString)
{
// Calling a string constructor doesn't call the actual constructor.
pResult.codePointerOrStubLookup.constLookup =
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.StringAllocator(targetMethod));
}
else if (pResult.exactContextNeedsRuntimeLookup)
else if (pResult->exactContextNeedsRuntimeLookup)
{
// Nothing to do... The generic handle lookup gets embedded in to the codegen
// during the jitting of the call.
@ -3240,7 +3252,7 @@ namespace Internal.JitInterface
// codegen emitted at crossgen time)
Debug.Assert(!forceUseRuntimeLookup);
pResult.codePointerOrStubLookup.constLookup =
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(targetMethod));
}
else
@ -3259,50 +3271,29 @@ namespace Internal.JitInterface
if (instParam != null)
{
pResult.instParamLookup = CreateConstLookupToSymbol(instParam);
pResult->instParamLookup = CreateConstLookupToSymbol(instParam);
}
if (!referencingArrayAddressMethod)
{
pResult.codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod));
}
else
{
// We don't want array Address method to be modeled in the generic dependency analysis.
// The method doesn't actually have runtime determined dependencies (won't do
// any generic lookups).
pResult.codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(targetMethod));
}
}
else if (targetMethod.AcquiresInstMethodTableFromThis())
{
pResult.codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod));
}
else
{
pResult.codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(targetMethod));
}
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(_compilation.NodeFactory.MethodEntrypoint(targetMethod));
}
pResult.nullInstanceCheck = resolvedCallVirt;
pResult->nullInstanceCheck = resolvedCallVirt;
}
else if (method.HasInstantiation)
{
// GVM Call Support
pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_LDVIRTFTN;
pResult.codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_VALUE;
pResult.nullInstanceCheck = true;
pResult->kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_LDVIRTFTN;
pResult->codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_VALUE;
pResult->nullInstanceCheck = true;
if (pResult.exactContextNeedsRuntimeLookup)
if (pResult->exactContextNeedsRuntimeLookup)
{
ComputeLookup(pResolvedToken.tokenContext,
GetRuntimeDeterminedObjectForToken(ref pResolvedToken),
ReadyToRunHelperId.MethodHandle,
ref pResult.codePointerOrStubLookup);
Debug.Assert(pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup);
ref pResult->codePointerOrStubLookup);
Debug.Assert(pResult->codePointerOrStubLookup.lookupKind.needsRuntimeLookup);
}
// RyuJIT will assert if we report CORINFO_CALLCONV_PARAMTYPE for a result of a ldvirtftn
@ -3313,21 +3304,21 @@ namespace Internal.JitInterface
else if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) == 0
&& targetMethod.OwningType.IsInterface)
{
pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_STUB;
pResult->kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_STUB;
if (pResult.exactContextNeedsRuntimeLookup)
if (pResult->exactContextNeedsRuntimeLookup)
{
ComputeLookup(pResolvedToken.tokenContext,
GetRuntimeDeterminedObjectForToken(ref pResolvedToken),
ReadyToRunHelperId.VirtualDispatchCell,
ref pResult.codePointerOrStubLookup);
Debug.Assert(pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup);
ref pResult->codePointerOrStubLookup);
Debug.Assert(pResult->codePointerOrStubLookup.lookupKind.needsRuntimeLookup);
}
else
{
pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = false;
pResult.codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_PVALUE;
pResult.codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle(
pResult->codePointerOrStubLookup.lookupKind.needsRuntimeLookup = false;
pResult->codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_PVALUE;
pResult->codePointerOrStubLookup.constLookup.addr = (void*)ObjectToHandle(
_compilation.NodeFactory.InterfaceDispatchCell(targetMethod
#if !SUPPORT_JIT
, _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled).ToString()
@ -3338,22 +3329,22 @@ namespace Internal.JitInterface
else if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) == 0
&& _compilation.HasFixedSlotVTable(targetMethod.OwningType))
{
pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_VTABLE;
pResult.nullInstanceCheck = true;
pResult->kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_VTABLE;
pResult->nullInstanceCheck = true;
}
else
{
ReadyToRunHelperId helperId;
if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0)
{
pResult.kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_LDVIRTFTN;
pResult->kind = CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_LDVIRTFTN;
helperId = ReadyToRunHelperId.ResolveVirtualFunction;
}
else
{
// CORINFO_CALL_CODE_POINTER tells the JIT that this is indirect
// call that should not be inlined.
pResult.kind = CORINFO_CALL_KIND.CORINFO_CALL_CODE_POINTER;
pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL_CODE_POINTER;
helperId = ReadyToRunHelperId.VirtualCall;
}
@ -3361,18 +3352,18 @@ namespace Internal.JitInterface
// We don't even need to keep track of the runtime-determined method being called because the system ensures
// that if e.g. Foo<__Canon>.GetHashCode is needed and we're generating a dictionary for Foo<string>,
// Foo<string>.GetHashCode is needed too.
if (pResult.exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface)
if (pResult->exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface)
{
// We need JitInterface changes to fully support this.
// If this is LDVIRTFTN of an interface method that is part of a verifiable delegate creation sequence,
// RyuJIT is not going to use this value.
Debug.Assert(helperId == ReadyToRunHelperId.ResolveVirtualFunction);
pResult.exactContextNeedsRuntimeLookup = false;
pResult.codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ExternSymbol("NYI_LDVIRTFTN"));
pResult->exactContextNeedsRuntimeLookup = false;
pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ExternSymbol("NYI_LDVIRTFTN"));
}
else
{
pResult.exactContextNeedsRuntimeLookup = false;
pResult->exactContextNeedsRuntimeLookup = false;
targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
// Get the slot defining method to make sure our virtual method use tracking gets this right.
@ -3380,42 +3371,42 @@ namespace Internal.JitInterface
MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ?
targetMethod : MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethod);
pResult.codePointerOrStubLookup.constLookup =
pResult->codePointerOrStubLookup.constLookup =
CreateConstLookupToSymbol(
_compilation.NodeFactory.ReadyToRunHelper(helperId, slotDefiningMethod));
}
// The current CoreRT ReadyToRun helpers do not handle null thisptr - ask the JIT to emit explicit null checks
// TODO: Optimize this
pResult.nullInstanceCheck = true;
pResult->nullInstanceCheck = true;
}
pResult.hMethod = ObjectToHandle(targetMethod);
pResult->hMethod = ObjectToHandle(targetMethod);
pResult.accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
pResult->accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
// We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
// need.
pResult.classFlags = getClassAttribsInternal(targetMethod.OwningType);
pResult->classFlags = getClassAttribsInternal(targetMethod.OwningType);
pResult.methodFlags = getMethodAttribsInternal(targetMethod);
Get_CORINFO_SIG_INFO(targetMethod, out pResult.sig, targetIsFatFunctionPointer);
pResult->methodFlags = getMethodAttribsInternal(targetMethod);
Get_CORINFO_SIG_INFO(targetMethod, &pResult->sig, targetIsFatFunctionPointer);
if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_VERIFICATION) != 0)
{
if (pResult.hMethod != pResolvedToken.hMethod)
if (pResult->hMethod != pResolvedToken.hMethod)
{
pResult.verMethodFlags = getMethodAttribsInternal(targetMethod);
Get_CORINFO_SIG_INFO(targetMethod, out pResult.verSig);
pResult->verMethodFlags = getMethodAttribsInternal(targetMethod);
Get_CORINFO_SIG_INFO(targetMethod, &pResult->verSig);
}
else
{
pResult.verMethodFlags = pResult.methodFlags;
pResult.verSig = pResult.sig;
pResult->verMethodFlags = pResult->methodFlags;
pResult->verSig = pResult->sig;
}
}
pResult._secureDelegateInvoke = 0;
pResult->_secureDelegateInvoke = 0;
}
private bool canAccessFamily(CORINFO_METHOD_STRUCT_* hCaller, CORINFO_CLASS_STRUCT_* hInstanceType)
@ -3803,6 +3794,9 @@ namespace Internal.JitInterface
if (this.MethodBeingCompiled.IsPInvoke)
flags.Set(CorJitFlag.CORJIT_FLAG_IL_STUB);
if (this.MethodBeingCompiled.IsNoOptimization)
flags.Set(CorJitFlag.CORJIT_FLAG_MIN_OPT);
return (uint)sizeof(CORJIT_FLAGS);
}
}

Просмотреть файл

@ -623,7 +623,7 @@ namespace Internal.JitInterface
CORINFO_FLG_NOGCCHECK = 0x00200000, // This method is FCALL that has no GC check. Don't put alone in loops
CORINFO_FLG_INTRINSIC = 0x00400000, // This method MAY have an intrinsic ID
CORINFO_FLG_CONSTRUCTOR = 0x00800000, // This method is an instance or type initializer
// CORINFO_FLG_UNUSED = 0x01000000,
CORINFO_FLG_AGGRESSIVE_OPT = 0x01000000, // The method may contain hot code and should be aggressively optimized if possible
// CORINFO_FLG_UNUSED = 0x02000000,
CORINFO_FLG_NOSECURITYWRAP = 0x04000000, // The method requires no security checks
CORINFO_FLG_DONT_INLINE = 0x10000000, // The method should not be inlined

Просмотреть файл

@ -91,9 +91,9 @@ CORINFO_RESOLVED_TOKEN*,ref CORINFO_RESOLVED_TOKEN,void*
CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,void*
CORINFO_EE_INFO*,ref CORINFO_EE_INFO,void*
CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT,void*
CORINFO_METHOD_INFO*,ref CORINFO_METHOD_INFO,void*
CORINFO_FIELD_INFO*,ref CORINFO_FIELD_INFO,void*
CORINFO_CALL_INFO*,ref CORINFO_CALL_INFO,void*
CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO*,void*
CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO*,void*
CORINFO_CALL_INFO*,CORINFO_CALL_INFO*,void*
DelegateCtorArgs*,ref DelegateCtorArgs,void*
ICorDynamicInfo*,IntPtr,void*
va_list,IntPtr
@ -137,9 +137,8 @@ CORINFO_FIELD_HANDLE,CORINFO_FIELD_STRUCT_*,void*
CORINFO_CLASS_HANDLE,CORINFO_CLASS_STRUCT_*,void*
CORINFO_ASSEMBLY_HANDLE,CORINFO_ASSEMBLY_STRUCT_*,void*
CORINFO_JUST_MY_CODE_HANDLE,CORINFO_JUST_MY_CODE_HANDLE_*,void*
CORINFO_MODULE_HANDLE*,ref CORINFO_MODULE_STRUCT_*,void*
CORINFO_MODULE_HANDLE_STAR,CORINFO_MODULE_STRUCT_**,void*
CORINFO_CLASS_HANDLE*,ref CORINFO_CLASS_STRUCT_*,void*
CORINFO_MODULE_HANDLE*,CORINFO_MODULE_STRUCT_**,void*
CORINFO_CLASS_HANDLE*,CORINFO_CLASS_STRUCT_**,void*
CORINFO_ARG_LIST_HANDLE,CORINFO_ARG_LIST_STRUCT_*,void*
CORINFO_VARARGS_HANDLE,IntPtr,void*
CORINFO_CONTEXT_HANDLE,CORINFO_CONTEXT_STRUCT*,void*
@ -211,7 +210,7 @@ FUNCTIONS
const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem)
void* LongLifetimeMalloc(size_t sz)
void LongLifetimeFree(void* obj)
size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE_STAR pModule, VOIDSTARSTAR ppIndirection)
size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection)
unsigned getClassSize(CORINFO_CLASS_HANDLE cls)
unsigned getClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, BOOL fDoubleAlignHint)
unsigned getClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs)

Просмотреть файл

@ -294,15 +294,15 @@ public:
union
{
vlReg vlReg;
vlStk vlStk;
vlRegReg vlRegReg;
vlRegStk vlRegStk;
vlStkReg vlStkReg;
vlStk2 vlStk2;
vlFPstk vlFPstk;
vlFixedVarArg vlFixedVarArg;
vlMemory vlMemory;
ICorDebugInfo::vlReg vlReg;
ICorDebugInfo::vlStk vlStk;
ICorDebugInfo::vlRegReg vlRegReg;
ICorDebugInfo::vlRegStk vlRegStk;
ICorDebugInfo::vlStkReg vlStkReg;
ICorDebugInfo::vlStk2 vlStk2;
ICorDebugInfo::vlFPstk vlFPstk;
ICorDebugInfo::vlFixedVarArg vlFixedVarArg;
ICorDebugInfo::vlMemory vlMemory;
};
};

Просмотреть файл

@ -824,7 +824,7 @@ enum CorInfoFlag
CORINFO_FLG_NOGCCHECK = 0x00200000, // This method is FCALL that has no GC check. Don't put alone in loops
CORINFO_FLG_INTRINSIC = 0x00400000, // This method MAY have an intrinsic ID
CORINFO_FLG_CONSTRUCTOR = 0x00800000, // This method is an instance or type initializer
// CORINFO_FLG_UNUSED = 0x01000000,
CORINFO_FLG_AGGRESSIVE_OPT = 0x01000000, // The method may contain hot code and should be aggressively optimized if possible
// CORINFO_FLG_UNUSED = 0x02000000,
CORINFO_FLG_NOSECURITYWRAP = 0x04000000, // The method requires no security checks
CORINFO_FLG_DONT_INLINE = 0x10000000, // The method should not be inlined
@ -2640,7 +2640,7 @@ public:
// result of calling getMemberParent.
virtual CorInfoType getFieldType(
CORINFO_FIELD_HANDLE field,
CORINFO_CLASS_HANDLE *structType,
CORINFO_CLASS_HANDLE *structType = NULL,
CORINFO_CLASS_HANDLE memberParent = NULL /* IN */
) = 0;

Просмотреть файл

@ -54,6 +54,11 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\MemoryManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\TlsOverPerCoreLockedStacksArrayPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Utilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\Reader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\ReaderBigEndian.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\ReaderLittleEndian.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\WriterBigEndian.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Binary\WriterLittleEndian.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Text\FormattingHelpers.CountDigits.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Byte.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Char.cs" />
@ -586,6 +591,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.Debug.cs" Condition="'$(Configuration)' == 'Debug'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Utf16Utility.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF32Encoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF7Encoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF8Encoding.cs" />

Просмотреть файл

@ -471,7 +471,7 @@ namespace System
/// because DebuggerDisplay should be a single property access or parameterless method call, so that the debugger
/// can use a fast path without using the expression evaluator.
///
/// See http://msdn.microsoft.com/en-us/library/x810d419.aspx
/// See https://docs.microsoft.com/en-us/visualstudio/debugger/using-the-debuggerdisplay-attribute
/// </summary>
private int InnerExceptionCount
{

Просмотреть файл

@ -0,0 +1,126 @@
// 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.Runtime.CompilerServices;
namespace System.Buffers.Binary
{
/// <summary>
/// Reads bytes as primitives with specific endianness
/// </summary>
/// <remarks>
/// For native formats, MemoryExtensions.Read{T}; should be used.
/// Use these helpers when you need to read specific endinanness.
/// </remarks>
public static partial class BinaryPrimitives
{
/// <summary>
/// This is a no-op and added only for consistency.
/// This allows the caller to read a struct of numeric primitives and reverse each field
/// rather than having to skip sbyte fields.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static sbyte ReverseEndianness(sbyte value)
{
return value;
}
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static short ReverseEndianness(short value)
{
return (short)((value & 0x00FF) << 8 | (value & 0xFF00) >> 8);
}
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReverseEndianness(int value) => (int)ReverseEndianness((uint)value);
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long ReverseEndianness(long value) => (long)ReverseEndianness((ulong)value);
/// <summary>
/// This is a no-op and added only for consistency.
/// This allows the caller to read a struct of numeric primitives and reverse each field
/// rather than having to skip byte fields.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte ReverseEndianness(byte value)
{
return value;
}
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReverseEndianness(ushort value)
{
// Don't need to AND with 0xFF00 or 0x00FF since the final
// cast back to ushort will clear out all bits above [ 15 .. 00 ].
// This is normally implemented via "movzx eax, ax" on the return.
// Alternatively, the compiler could elide the movzx instruction
// entirely if it knows the caller is only going to access "ax"
// instead of "eax" / "rax" when the function returns.
return (ushort)((value >> 8) + (value << 8));
}
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ReverseEndianness(uint value)
{
// This takes advantage of the fact that the JIT can detect
// ROL32 / ROR32 patterns and output the correct intrinsic.
//
// Input: value = [ ww xx yy zz ]
//
// First line generates : [ ww xx yy zz ]
// & [ 00 FF 00 FF ]
// = [ 00 xx 00 zz ]
// ROR32(8) = [ zz 00 xx 00 ]
//
// Second line generates: [ ww xx yy zz ]
// & [ FF 00 FF 00 ]
// = [ ww 00 yy 00 ]
// ROL32(8) = [ 00 yy 00 ww ]
//
// (sum) = [ zz yy xx ww ]
//
// Testing shows that throughput increases if the AND
// is performed before the ROL / ROR.
uint mask_xx_zz = (value & 0x00FF00FFU);
uint mask_ww_yy = (value & 0xFF00FF00U);
return ((mask_xx_zz >> 8) | (mask_xx_zz << 24))
+ ((mask_ww_yy << 8) | (mask_ww_yy >> 24));
}
/// <summary>
/// Reverses a primitive value - performs an endianness swap
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong ReverseEndianness(ulong value)
{
// Operations on 32-bit values have higher throughput than
// operations on 64-bit values, so decompose.
return ((ulong)ReverseEndianness((uint)value) << 32)
+ ReverseEndianness((uint)(value >> 32));
}
}
}

Просмотреть файл

@ -0,0 +1,193 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
public static partial class BinaryPrimitives
{
/// <summary>
/// Reads an Int16 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static short ReadInt16BigEndian(ReadOnlySpan<byte> source)
{
short result = MemoryMarshal.Read<short>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int32 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReadInt32BigEndian(ReadOnlySpan<byte> source)
{
int result = MemoryMarshal.Read<int>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int64 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long ReadInt64BigEndian(ReadOnlySpan<byte> source)
{
long result = MemoryMarshal.Read<long>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt16 out of a read-only span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReadUInt16BigEndian(ReadOnlySpan<byte> source)
{
ushort result = MemoryMarshal.Read<ushort>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt32 out of a read-only span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ReadUInt32BigEndian(ReadOnlySpan<byte> source)
{
uint result = MemoryMarshal.Read<uint>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt64 out of a read-only span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong ReadUInt64BigEndian(ReadOnlySpan<byte> source)
{
ulong result = MemoryMarshal.Read<ulong>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int16 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain an Int16, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt16BigEndian(ReadOnlySpan<byte> source, out short value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads an Int32 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain an Int32, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt32BigEndian(ReadOnlySpan<byte> source, out int value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads an Int64 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain an Int64, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt64BigEndian(ReadOnlySpan<byte> source, out long value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt16 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain a UInt16, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt16BigEndian(ReadOnlySpan<byte> source, out ushort value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt32 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain a UInt32, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt32BigEndian(ReadOnlySpan<byte> source, out uint value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt64 out of a read-only span of bytes as big endian.
/// <returns>If the span is too small to contain a UInt64, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt64BigEndian(ReadOnlySpan<byte> source, out ulong value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
}
}

Просмотреть файл

@ -0,0 +1,192 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
public static partial class BinaryPrimitives
{
/// <summary>
/// Reads an Int16 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static short ReadInt16LittleEndian(ReadOnlySpan<byte> source)
{
short result = MemoryMarshal.Read<short>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int32 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReadInt32LittleEndian(ReadOnlySpan<byte> source)
{
int result = MemoryMarshal.Read<int>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int64 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long ReadInt64LittleEndian(ReadOnlySpan<byte> source)
{
long result = MemoryMarshal.Read<long>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt16 out of a read-only span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ReadUInt16LittleEndian(ReadOnlySpan<byte> source)
{
ushort result = MemoryMarshal.Read<ushort>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt32 out of a read-only span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ReadUInt32LittleEndian(ReadOnlySpan<byte> source)
{
uint result = MemoryMarshal.Read<uint>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads a UInt64 out of a read-only span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong ReadUInt64LittleEndian(ReadOnlySpan<byte> source)
{
ulong result = MemoryMarshal.Read<ulong>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
}
return result;
}
/// <summary>
/// Reads an Int16 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain an Int16, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt16LittleEndian(ReadOnlySpan<byte> source, out short value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads an Int32 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain an Int32, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt32LittleEndian(ReadOnlySpan<byte> source, out int value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads an Int64 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain an Int64, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadInt64LittleEndian(ReadOnlySpan<byte> source, out long value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt16 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain a UInt16, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt16LittleEndian(ReadOnlySpan<byte> source, out ushort value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt32 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain a UInt32, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt32LittleEndian(ReadOnlySpan<byte> source, out uint value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
/// <summary>
/// Reads a UInt64 out of a read-only span of bytes as little endian.
/// <returns>If the span is too small to contain a UInt64, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryReadUInt64LittleEndian(ReadOnlySpan<byte> source, out ulong value)
{
bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return success;
}
}
}

Просмотреть файл

@ -0,0 +1,180 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
public static partial class BinaryPrimitives
{
/// <summary>
/// Writes an Int16 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt16BigEndian(Span<byte> destination, short value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt32BigEndian(Span<byte> destination, int value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt64BigEndian(Span<byte> destination, long value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt16 into a span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt16BigEndian(Span<byte> destination, ushort value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt32 into a span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt32BigEndian(Span<byte> destination, uint value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt64 into a span of bytes as big endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt64BigEndian(Span<byte> destination, ulong value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int16 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt16BigEndian(Span<byte> destination, short value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt32BigEndian(Span<byte> destination, int value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt64BigEndian(Span<byte> destination, long value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt16 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt16BigEndian(Span<byte> destination, ushort value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt32 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt32BigEndian(Span<byte> destination, uint value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt64 into a span of bytes as big endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt64BigEndian(Span<byte> destination, ulong value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
}
}

Просмотреть файл

@ -0,0 +1,180 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
public static partial class BinaryPrimitives
{
/// <summary>
/// Writes an Int16 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt16LittleEndian(Span<byte> destination, short value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt32LittleEndian(Span<byte> destination, int value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteInt64LittleEndian(Span<byte> destination, long value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt16 into a span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt16LittleEndian(Span<byte> destination, ushort value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt32 into a span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt32LittleEndian(Span<byte> destination, uint value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Write a UInt64 into a span of bytes as little endian.
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void WriteUInt64LittleEndian(Span<byte> destination, ulong value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int16 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt16LittleEndian(Span<byte> destination, short value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt32LittleEndian(Span<byte> destination, int value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteInt64LittleEndian(Span<byte> destination, long value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt16 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt16LittleEndian(Span<byte> destination, ushort value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt32 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt32LittleEndian(Span<byte> destination, uint value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
/// Write a UInt64 into a span of bytes as little endian.
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryWriteUInt64LittleEndian(Span<byte> destination, ulong value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
return MemoryMarshal.TryWrite(destination, ref value);
}
}
}

Просмотреть файл

@ -358,7 +358,7 @@ namespace System.Diagnostics.Tracing
/// <summary>
/// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
/// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
/// documented at in EventManifest Schema https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-schema.
/// This is the preferred way of generating a manifest to be embedded in the ETW stream as it is fast and
/// the fact that it only includes localized entries for the current UI culture is an acceptable tradeoff.
/// </summary>
@ -372,7 +372,7 @@ namespace System.Diagnostics.Tracing
}
/// <summary>
/// Returns a string of the XML manifest associated with the eventSourceType. The scheme for this XML is
/// documented at in EventManifest Schema http://msdn.microsoft.com/en-us/library/aa384043(VS.85).aspx.
/// documented at in EventManifest Schema https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-schema.
/// Pass EventManifestOptions.AllCultures when generating a manifest to be registered on the machine. This
/// ensures that the entries in the event log will be "optimally" localized.
/// </summary>
@ -4914,7 +4914,7 @@ namespace System.Diagnostics.Tracing
/// <summary>
/// Specifies an SDDL access descriptor that controls access to the log file that backs the channel.
/// See MSDN ((http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx) for details.
/// See MSDN (https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-channeltype-complextype) for details.
/// </summary>
public string Access { get; set; }
@ -4948,7 +4948,7 @@ namespace System.Diagnostics.Tracing
#if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
/// <summary>
/// Allowed isolation levels. See MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/aa382741.aspx)
/// Allowed isolation levels. See MSDN (https://docs.microsoft.com/en-us/windows/desktop/WES/eventmanifestschema-channeltype-complextype)
/// for the default permissions associated with each level. EventChannelIsolation and Access allows control over the
/// access permissions for the channel and backing file.
/// </summary>

Просмотреть файл

@ -393,7 +393,7 @@ namespace System.Globalization
double approx = EstimatePrior(LongitudeSpring, MiddayAtPersianObservationSite(date));
long lowerBoundNewYearDay = (long)Math.Floor(approx) - 1;
long upperBoundNewYearDay = lowerBoundNewYearDay + 3; // estimate is generally within a day of the actual occurrance (at the limits, the error expands, since the calculations rely on the mean tropical year which changes...)
long upperBoundNewYearDay = lowerBoundNewYearDay + 3; // estimate is generally within a day of the actual occurrence (at the limits, the error expands, since the calculations rely on the mean tropical year which changes...)
long day = lowerBoundNewYearDay;
for (; day != upperBoundNewYearDay; ++day)
{

Просмотреть файл

@ -13,9 +13,19 @@
////////////////////////////////////////////////////////////////////////////
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
using Internal.Runtime.CompilerServices;
#if BIT64
using nuint = System.UInt64;
using nint = System.Int64;
#else // BIT64
using nuint = System.UInt32;
using nint = System.Int32;
#endif // BIT64
namespace System.Globalization
{
@ -23,9 +33,9 @@ namespace System.Globalization
{
private enum Tristate : byte
{
NotInitialized,
True,
False,
NotInitialized = 0,
False = 1,
True = 2
}
private string _listSeparator;
@ -180,7 +190,7 @@ namespace System.Globalization
// have different casing semantics from the file systems in Win32.
//
////////////////////////////////////////////////////////////////////////
public unsafe virtual char ToLower(char c)
public virtual char ToLower(char c)
{
if (_invariantMode || (IsAscii(c) && IsAsciiCasingSameAsInvariant))
{
@ -190,7 +200,7 @@ namespace System.Globalization
return ChangeCase(c, toUpper: false);
}
public unsafe virtual string ToLower(string str)
public virtual string ToLower(string str)
{
if (str == null) { throw new ArgumentNullException(nameof(str)); }
@ -199,7 +209,7 @@ namespace System.Globalization
return ToLowerAsciiInvariant(str);
}
return ChangeCase(str, toUpper: false);
return ChangeCaseCommon<ToLowerConversion>(str);
}
private unsafe char ChangeCase(char c, bool toUpper)
@ -210,9 +220,140 @@ namespace System.Globalization
ChangeCase(&c, 1, &dst, 1, toUpper);
return dst;
}
private unsafe string ChangeCase(string source, bool toUpper)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ChangeCaseToLower(ReadOnlySpan<char> source, Span<char> destination)
{
Debug.Assert(destination.Length >= source.Length);
ChangeCaseCommon<ToLowerConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ChangeCaseToUpper(ReadOnlySpan<char> source, Span<char> destination)
{
Debug.Assert(destination.Length >= source.Length);
ChangeCaseCommon<ToUpperConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ChangeCaseCommon<TConversion>(ReadOnlySpan<char> source, Span<char> destination) where TConversion : struct
{
Debug.Assert(destination.Length >= source.Length);
ChangeCaseCommon<TConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length);
}
private unsafe void ChangeCaseCommon<TConversion>(ref char source, ref char destination, int charCount) where TConversion : struct
{
Debug.Assert(typeof(TConversion) == typeof(ToUpperConversion) || typeof(TConversion) == typeof(ToLowerConversion));
bool toUpper = typeof(TConversion) == typeof(ToUpperConversion); // JIT will treat this as a constant in release builds
Debug.Assert(!_invariantMode);
Debug.Assert(charCount >= 0);
if (charCount == 0)
{
goto Return;
}
fixed (char* pSource = &source)
fixed (char* pDestination = &destination)
{
nuint currIdx = 0; // in chars
if (IsAsciiCasingSameAsInvariant)
{
// Read 4 chars (two 32-bit integers) at a time
if (charCount >= 4)
{
nuint lastIndexWhereCanReadFourChars = (uint)charCount - 4;
do
{
// This is a mostly branchless case change routine. Generally speaking, we assume that the majority
// of input is ASCII, so the 'if' checks below should normally evaluate to false. However, within
// the ASCII data, we expect that characters of either case might be about equally distributed, so
// we want the case change operation itself to be branchless. This gives optimal performance in the
// common case. We also expect that developers aren't passing very long (16+ character) strings into
// this method, so we won't bother vectorizing until data shows us that it's worthwhile to do so.
uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx);
if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue))
{
goto NonAscii;
}
tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue);
Unsafe.WriteUnaligned<uint>(pDestination + currIdx, tempValue);
tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx + 2);
if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue))
{
goto NonAsciiSkipTwoChars;
}
tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue);
Unsafe.WriteUnaligned<uint>(pDestination + currIdx + 2, tempValue);
currIdx += 4;
} while (currIdx <= lastIndexWhereCanReadFourChars);
// At this point, there are fewer than 4 characters remaining to convert.
Debug.Assert((uint)charCount - currIdx < 4);
}
// If there are 2 or 3 characters left to convert, we'll convert 2 of them now.
if ((charCount & 2) != 0)
{
uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx);
if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue))
{
goto NonAscii;
}
tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue);
Unsafe.WriteUnaligned<uint>(pDestination + currIdx, tempValue);
currIdx += 2;
}
// If there's a single character left to convert, do it now.
if ((charCount & 1) != 0)
{
uint tempValue = pSource[currIdx];
if (tempValue > 0x7Fu)
{
goto NonAscii;
}
tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue);
pDestination[currIdx] = (char)tempValue;
}
// And we're finished!
goto Return;
// If we reached this point, we found non-ASCII data.
// Fall back down the p/invoke code path.
NonAsciiSkipTwoChars:
currIdx += 2;
NonAscii:
Debug.Assert(currIdx < (uint)charCount, "We somehow read past the end of the buffer.");
charCount -= (int)currIdx;
}
// We encountered non-ASCII data and therefore can't perform invariant case conversion; or the requested culture
// has a case conversion that's different from the invariant culture, even for ASCII data (e.g., tr-TR converts
// 'i' (U+0069) to Latin Capital Letter I With Dot Above (U+0130)).
ChangeCase(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper);
}
Return:
return;
}
private unsafe string ChangeCaseCommon<TConversion>(string source) where TConversion : struct
{
Debug.Assert(typeof(TConversion) == typeof(ToUpperConversion) || typeof(TConversion) == typeof(ToLowerConversion));
bool toUpper = typeof(TConversion) == typeof(ToUpperConversion); // JIT will treat this as a constant in release builds
Debug.Assert(!_invariantMode);
Debug.Assert(source != null);
@ -222,199 +363,93 @@ namespace System.Globalization
return string.Empty;
}
int sourcePos = 0;
string result = null;
// If this culture's casing for ASCII is the same as invariant, try to take
// a fast path that'll work in managed code and ASCII rather than calling out
// to the OS for culture-aware casing.
if (IsAsciiCasingSameAsInvariant)
{
if (toUpper)
{
// Loop through each character.
for (sourcePos = 0; sourcePos < source.Length; sourcePos++)
{
// If the character is lower-case, we're going to need to allocate a string.
char c = source[sourcePos];
if ((uint)(c - 'a') <= 'z' - 'a')
{
// Allocate the result string.
result = string.FastAllocateString(source.Length);
fixed (char* pResult = result)
{
// Store all of characters examined thus far.
if (sourcePos > 0)
{
source.AsSpan(0, sourcePos).CopyTo(new Span<char>(pResult, sourcePos));
}
// And store the current character, upper-cased.
char* d = pResult + sourcePos;
*d++ = (char)(c & ~0x20);
sourcePos++;
// Then continue looping through the remainder of the characters. If we hit
// a non-ASCII character, bail to fall back to culture-aware casing.
for (; sourcePos < source.Length; sourcePos++)
{
c = source[sourcePos];
if ((uint)(c - 'a') <= 'z' - 'a')
{
*d++ = (char)(c & ~0x20);
}
else if (!IsAscii(c))
{
break;
}
else
{
*d++ = c;
}
}
}
break;
}
else if (!IsAscii(c))
{
// The character isn't ASCII; bail to fall back to a culture-aware casing.
break;
}
}
}
else // toUpper == false
{
// Loop through each character.
for (sourcePos = 0; sourcePos < source.Length; sourcePos++)
{
// If the character is upper-case, we're going to need to allocate a string.
char c = source[sourcePos];
if ((uint)(c - 'A') <= 'Z' - 'A')
{
// Allocate the result string.
result = string.FastAllocateString(source.Length);
fixed (char* pResult = result)
{
// Store all of characters examined thus far.
if (sourcePos > 0)
{
source.AsSpan(0, sourcePos).CopyTo(new Span<char>(pResult, sourcePos));
}
// And store the current character, lower-cased.
char* d = pResult + sourcePos;
*d++ = (char)(c | 0x20);
sourcePos++;
// Then continue looping through the remainder of the characters. If we hit
// a non-ASCII character, bail to fall back to culture-aware casing.
for (; sourcePos < source.Length; sourcePos++)
{
c = source[sourcePos];
if ((uint)(c - 'A') <= 'Z' - 'A')
{
*d++ = (char)(c | 0x20);
}
else if (!IsAscii(c))
{
break;
}
else
{
*d++ = c;
}
}
}
break;
}
else if (!IsAscii(c))
{
// The character isn't ASCII; bail to fall back to a culture-aware casing.
break;
}
}
}
// If we successfully iterated through all of the characters, we didn't need to fall back
// to culture-aware casing. In that case, if we allocated a result string, use it, otherwise
// just return the original string, as no modifications were necessary.
if (sourcePos == source.Length)
{
return result ?? source;
}
}
// Falling back to culture-aware casing. Make sure we have a result string to write into.
// If we need to allocate the result string, we'll also need to copy over to it any
// characters already examined.
if (result == null)
{
result = string.FastAllocateString(source.Length);
if (sourcePos > 0)
{
fixed (char* pResult = result)
{
source.AsSpan(0, sourcePos).CopyTo(new Span<char>(pResult, sourcePos));
}
}
}
// Do the casing operation on everything after what we already processed.
fixed (char* pSource = source)
{
fixed (char* pResult = result)
{
ChangeCase(pSource + sourcePos, source.Length - sourcePos, pResult + sourcePos, result.Length - sourcePos, toUpper);
}
}
nuint currIdx = 0; // in chars
return result;
}
internal unsafe void ChangeCase(ReadOnlySpan<char> source, Span<char> destination, bool toUpper)
{
Debug.Assert(!_invariantMode);
Debug.Assert(destination.Length >= source.Length);
if (source.IsEmpty)
{
return;
}
fixed (char* pSource = &MemoryMarshal.GetReference(source))
fixed (char* pResult = &MemoryMarshal.GetReference(destination))
{
// If this culture's casing for ASCII is the same as invariant, try to take
// a fast path that'll work in managed code and ASCII rather than calling out
// to the OS for culture-aware casing.
if (IsAsciiCasingSameAsInvariant)
{
int length = 0;
char* a = pSource, b = pResult;
if (toUpper)
// Read 2 chars (one 32-bit integer) at a time
if (source.Length >= 2)
{
while (length < source.Length && *a < 0x80)
nuint lastIndexWhereCanReadTwoChars = (uint)source.Length - 2;
do
{
*b++ = ToUpperAsciiInvariant(*a++);
length++;
}
// See the comments in ChangeCaseCommon<TConversion>(ROS<char>, Span<char>) for a full explanation of the below code.
uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx);
if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue))
{
goto NotAscii;
}
if ((toUpper) ? Utf16Utility.UInt32ContainsAnyLowercaseAsciiChar(tempValue) : Utf16Utility.UInt32ContainsAnyUppercaseAsciiChar(tempValue))
{
goto AsciiMustChangeCase;
}
currIdx += 2;
} while (currIdx <= lastIndexWhereCanReadTwoChars);
}
else
// If there's a single character left to convert, do it now.
if ((source.Length & 1) != 0)
{
while (length < source.Length && *a < 0x80)
uint tempValue = pSource[currIdx];
if (tempValue > 0x7Fu)
{
*b++ = ToLowerAsciiInvariant(*a++);
length++;
goto NotAscii;
}
if ((toUpper) ? ((tempValue - 'a') <= (uint)('z' - 'a')) : ((tempValue - 'A') <= (uint)('Z' - 'A')))
{
goto AsciiMustChangeCase;
}
}
if (length != source.Length)
// We got through all characters without finding anything that needed to change - done!
return source;
AsciiMustChangeCase:
{
ChangeCase(a, source.Length - length, b, destination.Length - length, toUpper);
// We reached ASCII data that requires a case change.
// This will necessarily allocate a new string, but let's try to stay within the managed (non-localization tables)
// conversion code path if we can.
string result = string.FastAllocateString(source.Length); // changing case uses simple folding: doesn't change UTF-16 code unit count
// copy existing known-good data into the result
Span<char> resultSpan = new Span<char>(ref result.GetRawStringData(), result.Length);
source.AsSpan(0, (int)currIdx).CopyTo(resultSpan);
// and re-run the fast span-based logic over the remainder of the data
ChangeCaseCommon<TConversion>(source.AsSpan((int)currIdx), resultSpan.Slice((int)currIdx));
return result;
}
}
else
NotAscii:
{
ChangeCase(pSource, source.Length, pResult, destination.Length, toUpper);
// We reached non-ASCII data *or* the requested culture doesn't map ASCII data the same way as the invariant culture.
// In either case we need to fall back to the localization tables.
string result = string.FastAllocateString(source.Length); // changing case uses simple folding: doesn't change UTF-16 code unit count
if (currIdx > 0)
{
// copy existing known-good data into the result
Span<char> resultSpan = new Span<char>(ref result.GetRawStringData(), result.Length);
source.AsSpan(0, (int)currIdx).CopyTo(resultSpan);
}
// and run the culture-aware logic over the remainder of the data
fixed (char* pResult = result)
{
ChangeCase(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper);
}
return result;
}
}
}
@ -548,7 +583,7 @@ namespace System.Globalization
// have different casing semantics from the file systems in Win32.
//
////////////////////////////////////////////////////////////////////////
public unsafe virtual char ToUpper(char c)
public virtual char ToUpper(char c)
{
if (_invariantMode || (IsAscii(c) && IsAsciiCasingSameAsInvariant))
{
@ -558,7 +593,7 @@ namespace System.Globalization
return ChangeCase(c, toUpper: true);
}
public unsafe virtual string ToUpper(string str)
public virtual string ToUpper(string str)
{
if (str == null) { throw new ArgumentNullException(nameof(str)); }
@ -567,7 +602,7 @@ namespace System.Globalization
return ToUpperAsciiInvariant(str);
}
return ChangeCase(str, toUpper: true);
return ChangeCaseCommon<ToUpperConversion>(str);
}
internal static char ToUpperAsciiInvariant(char c)
@ -586,18 +621,26 @@ namespace System.Globalization
private bool IsAsciiCasingSameAsInvariant
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_isAsciiCasingSameAsInvariant == Tristate.NotInitialized)
{
_isAsciiCasingSameAsInvariant = CultureInfo.GetCultureInfo(_textInfoName).CompareInfo.Compare("abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
CompareOptions.IgnoreCase) == 0 ? Tristate.True : Tristate.False;
PopulateIsAsciiCasingSameAsInvariant();
}
return _isAsciiCasingSameAsInvariant == Tristate.True;
Debug.Assert(_isAsciiCasingSameAsInvariant == Tristate.True || _isAsciiCasingSameAsInvariant == Tristate.False);
return (_isAsciiCasingSameAsInvariant == Tristate.True);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void PopulateIsAsciiCasingSameAsInvariant()
{
bool compareResult = CultureInfo.GetCultureInfo(_textInfoName).CompareInfo.Compare("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", CompareOptions.IgnoreCase) == 0;
_isAsciiCasingSameAsInvariant = (compareResult) ? Tristate.True : Tristate.False;
}
// IsRightToLeft
//
// Returns true if the dominant direction of text and UI such as the relative position of buttons and scroll bars
@ -820,7 +863,7 @@ namespace System.Globalization
else
{
Span<char> dst = stackalloc char[2];
ChangeCase(src, dst, toUpper: true);
ChangeCaseToUpper(src, dst);
result.Append(dst);
}
inputIndex++;
@ -909,5 +952,11 @@ namespace System.Globalization
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter);
}
// A dummy struct that is used for 'ToUpper' in generic parameters
private readonly struct ToUpperConversion { }
// A dummy struct that is used for 'ToLower' in generic parameters
private readonly struct ToLowerConversion { }
}
}

Просмотреть файл

@ -35,4 +35,3 @@ namespace System
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -64,25 +64,25 @@ namespace System.IO
/// <summary>Whether the file stream's handle has been exposed.</summary>
private bool _exposedHandle;
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead. https://go.microsoft.com/fwlink/?linkid=14202")]
public FileStream(IntPtr handle, FileAccess access)
: this(handle, access, true, DefaultBufferSize, false)
{
}
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. https://go.microsoft.com/fwlink/?linkid=14202")]
public FileStream(IntPtr handle, FileAccess access, bool ownsHandle)
: this(handle, access, ownsHandle, DefaultBufferSize, false)
{
}
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. https://go.microsoft.com/fwlink/?linkid=14202")]
public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize)
: this(handle, access, ownsHandle, bufferSize, false)
{
}
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync) instead, and optionally make a new SafeFileHandle with ownsHandle=false if needed. https://go.microsoft.com/fwlink/?linkid=14202")]
public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync)
{
SafeFileHandle safeHandle = new SafeFileHandle(handle, ownsHandle: ownsHandle);
@ -244,7 +244,7 @@ namespace System.IO
}
}
[Obsolete("This property has been deprecated. Please use FileStream's SafeFileHandle property instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This property has been deprecated. Please use FileStream's SafeFileHandle property instead. https://go.microsoft.com/fwlink/?linkid=14202")]
public virtual IntPtr Handle { get { return SafeFileHandle.DangerousGetHandle(); } }
public virtual void Lock(long position, long length)

Просмотреть файл

@ -228,7 +228,7 @@ namespace System
if (GlobalizationMode.Invariant)
TextInfo.ToLowerAsciiInvariant(source, destination);
else
culture.TextInfo.ChangeCase(source, destination, toUpper: false);
culture.TextInfo.ChangeCaseToLower(source, destination);
return source.Length;
}
@ -250,7 +250,7 @@ namespace System
if (GlobalizationMode.Invariant)
TextInfo.ToLowerAsciiInvariant(source, destination);
else
CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: false);
CultureInfo.InvariantCulture.TextInfo.ChangeCaseToLower(source, destination);
return source.Length;
}
@ -279,7 +279,7 @@ namespace System
if (GlobalizationMode.Invariant)
TextInfo.ToUpperAsciiInvariant(source, destination);
else
culture.TextInfo.ChangeCase(source, destination, toUpper: true);
culture.TextInfo.ChangeCaseToUpper(source, destination);
return source.Length;
}
@ -301,7 +301,7 @@ namespace System
if (GlobalizationMode.Invariant)
TextInfo.ToUpperAsciiInvariant(source, destination);
else
CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: true);
CultureInfo.InvariantCulture.TextInfo.ChangeCaseToUpper(source, destination);
return source.Length;
}

Просмотреть файл

@ -32,7 +32,7 @@ namespace System
private const int UInt64Precision = 20;
/// <summary>256-element map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.</summary>
private static readonly int[] s_charToHexLookup =
internal static readonly int[] s_charToHexLookup =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
@ -214,7 +214,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
if (!TryParseUInt32HexNumberStyle(value, styles, info, out uint hexResult, ref overflow))
if (!TryParseUInt32HexNumberStyle(value, styles, out uint hexResult, ref overflow))
{
ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int32));
}
@ -247,7 +247,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
if (!TryParseUInt64HexNumberStyle(value, styles, info, out ulong hexResult, ref overflow))
if (!TryParseUInt64HexNumberStyle(value, styles, out ulong hexResult, ref overflow))
{
ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_Int64));
}
@ -282,7 +282,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
if (!TryParseUInt32HexNumberStyle(value, styles, info, out result, ref overflow))
if (!TryParseUInt32HexNumberStyle(value, styles, out result, ref overflow))
{
ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt32));
}
@ -316,7 +316,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
if (!TryParseUInt64HexNumberStyle(value, styles, info, out result, ref overflow))
if (!TryParseUInt64HexNumberStyle(value, styles, out result, ref overflow))
{
ThrowOverflowOrFormatException(overflow, nameof(SR.Overflow_UInt64));
}
@ -556,7 +556,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
return TryParseUInt32HexNumberStyle(value, styles, info, out Unsafe.As<int, uint>(ref result), ref overflow);
return TryParseUInt32HexNumberStyle(value, styles, out Unsafe.As<int, uint>(ref result), ref overflow);
}
NumberBuffer number = default;
@ -887,7 +887,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
return TryParseUInt64HexNumberStyle(value, styles, info, out Unsafe.As<long, ulong>(ref result), ref overflow);
return TryParseUInt64HexNumberStyle(value, styles, out Unsafe.As<long, ulong>(ref result), ref overflow);
}
NumberBuffer number = default;
@ -908,7 +908,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
return TryParseUInt32HexNumberStyle(value, styles, info, out result, ref overflow);
return TryParseUInt32HexNumberStyle(value, styles, out result, ref overflow);
}
NumberBuffer number = default;
@ -1070,7 +1070,7 @@ namespace System
/// <summary>Parses uint limited to styles that make up NumberStyles.HexNumber.</summary>
private static bool TryParseUInt32HexNumberStyle(
ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out uint result, ref bool failureIsOverflow)
ReadOnlySpan<char> value, NumberStyles styles, out uint result, ref bool failureIsOverflow)
{
Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format");
Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");
@ -1186,7 +1186,7 @@ namespace System
if ((styles & NumberStyles.AllowHexSpecifier) != 0)
{
bool overflow = false;
return TryParseUInt64HexNumberStyle(value, styles, info, out result, ref overflow);
return TryParseUInt64HexNumberStyle(value, styles, out result, ref overflow);
}
NumberBuffer number = default;
@ -1348,7 +1348,7 @@ namespace System
/// <summary>Parses ulong limited to styles that make up NumberStyles.HexNumber.</summary>
private static bool TryParseUInt64HexNumberStyle(
ReadOnlySpan<char> value, NumberStyles styles, NumberFormatInfo info, out ulong result, ref bool failureIsOverflow)
ReadOnlySpan<char> value, NumberStyles styles, out ulong result, ref bool failureIsOverflow)
{
Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format");
Debug.Assert(!failureIsOverflow, $"failureIsOverflow should have been initialized to false");

Просмотреть файл

@ -178,7 +178,7 @@ namespace System.Reflection
public static Assembly Load(byte[] rawAssembly) => Load(rawAssembly, rawSymbolStore: null);
[Obsolete("This method has been deprecated. Please use Assembly.Load() instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This method has been deprecated. Please use Assembly.Load() instead. https://go.microsoft.com/fwlink/?linkid=14202")]
public static Assembly LoadWithPartialName(string partialName)
{
if (partialName == null)

Просмотреть файл

@ -9,14 +9,14 @@ namespace System.Reflection
{
private AssemblyNameFlags _flags;
[Obsolete("This constructor has been deprecated. Please use AssemblyFlagsAttribute(AssemblyNameFlags) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use AssemblyFlagsAttribute(AssemblyNameFlags) instead. https://go.microsoft.com/fwlink/?linkid=14202")]
[CLSCompliant(false)]
public AssemblyFlagsAttribute(uint flags)
{
_flags = (AssemblyNameFlags)flags;
}
[Obsolete("This property has been deprecated. Please use AssemblyFlags instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This property has been deprecated. Please use AssemblyFlags instead. https://go.microsoft.com/fwlink/?linkid=14202")]
[CLSCompliant(false)]
public uint Flags
{
@ -28,7 +28,7 @@ namespace System.Reflection
get { return (int)_flags; }
}
[Obsolete("This constructor has been deprecated. Please use AssemblyFlagsAttribute(AssemblyNameFlags) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This constructor has been deprecated. Please use AssemblyFlagsAttribute(AssemblyNameFlags) instead. https://go.microsoft.com/fwlink/?linkid=14202")]
public AssemblyFlagsAttribute(int assemblyFlags)
{
_flags = (AssemblyNameFlags)assemblyFlags;

Просмотреть файл

@ -24,7 +24,7 @@ namespace System.Reflection.Emit
Cond_Branch = 3,
Meta = 4,
Next = 5,
[Obsolete("This API has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This API has been deprecated. https://go.microsoft.com/fwlink/?linkid=14202")]
Phi = 6,
Return = 7,
Throw = 8,

Просмотреть файл

@ -18,7 +18,7 @@ namespace System.Reflection.Emit
{
public enum OpCodeType
{
[Obsolete("This API has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This API has been deprecated. https://go.microsoft.com/fwlink/?linkid=14202")]
Annotation = 0,
Macro = 1,
Nternal = 2,

Просмотреть файл

@ -24,7 +24,7 @@ namespace System.Reflection.Emit
InlineI8 = 3,
InlineMethod = 4,
InlineNone = 5,
[Obsolete("This API has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
[Obsolete("This API has been deprecated. https://go.microsoft.com/fwlink/?linkid=14202")]
InlinePhi = 6,
InlineR = 7,
InlineSig = 9,

Просмотреть файл

@ -16,6 +16,7 @@ namespace System.Runtime.CompilerServices
NoOptimization = 0x0040,
PreserveSig = 0x0080,
AggressiveInlining = 0x0100,
AggressiveOptimization = 0x0200,
InternalCall = 0x1000
}
}

Просмотреть файл

@ -408,51 +408,103 @@ namespace System.Runtime.Intrinsics.X86
/// </summary>
public static Vector256<T> BroadcastScalarToVector256<T>(Vector128<T> value) where T : struct { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastb_epi8 (__m128i a)
/// VPBROADCASTB ymm, m8
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<byte> BroadcastScalarToVector256(byte* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastb_epi8 (__m128i a)
/// VPBROADCASTB ymm, m8
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<sbyte> BroadcastScalarToVector256(sbyte* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastw_epi16 (__m128i a)
/// VPBROADCASTW ymm, m16
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<short> BroadcastScalarToVector256(short* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastw_epi16 (__m128i a)
/// VPBROADCASTW ymm, m16
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ushort> BroadcastScalarToVector256(ushort* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastd_epi32 (__m128i a)
/// VPBROADCASTD ymm, m32
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<int> BroadcastScalarToVector256(int* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastd_epi32 (__m128i a)
/// VPBROADCASTD ymm, m32
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<uint> BroadcastScalarToVector256(uint* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastq_epi64 (__m128i a)
/// VPBROADCASTQ ymm, m64
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<long> BroadcastScalarToVector256(long* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastq_epi64 (__m128i a)
/// VPBROADCASTQ ymm, m64
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ulong> BroadcastScalarToVector256(ulong* source) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m8
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<sbyte> BroadcastVector128ToVector256(sbyte* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m8
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<byte> BroadcastVector128ToVector256(byte* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m16
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<short> BroadcastVector128ToVector256(short* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m16
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ushort> BroadcastVector128ToVector256(ushort* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m32
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<int> BroadcastVector128ToVector256(int* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m32
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<uint> BroadcastVector128ToVector256(uint* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m64
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<long> BroadcastVector128ToVector256(long* address) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m64
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ulong> BroadcastVector128ToVector256(ulong* address) { throw new PlatformNotSupportedException(); }
@ -1483,17 +1535,17 @@ namespace System.Runtime.Intrinsics.X86
/// <summary>
/// __m256i _mm256_permutevar8x32_epi32 (__m256i a, __m256i idx)
/// VPERMD ymm, ymm/m256, imm8
/// VPERMD ymm, ymm/m256, ymm
/// </summary>
public static Vector256<int> PermuteVar8x32(Vector256<int> left, Vector256<int> control) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_permutevar8x32_epi32 (__m256i a, __m256i idx)
/// VPERMD ymm, ymm/m256, imm8
/// VPERMD ymm, ymm/m256, ymm
/// </summary>
public static Vector256<uint> PermuteVar8x32(Vector256<uint> left, Vector256<uint> control) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256 _mm256_permutevar8x32_ps (__m256 a, __m256i idx)
/// VPERMPS ymm, ymm/m256, imm8
/// VPERMPS ymm, ymm/m256, ymm
/// </summary>
public static Vector256<float> PermuteVar8x32(Vector256<float> left, Vector256<int> control) { throw new PlatformNotSupportedException(); }
@ -1833,12 +1885,12 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<byte> Shuffle(Vector256<byte> value, Vector256<byte> mask) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_shuffle_epi32 (__m256i a, const int imm8)
/// VPSHUFD ymm, ymm, ymm/m256
/// VPSHUFD ymm, ymm/m256, imm8
/// </summary>
public static Vector256<int> Shuffle(Vector256<int> value, byte control) { throw new PlatformNotSupportedException(); }
/// <summary>
/// __m256i _mm256_shuffle_epi32 (__m256i a, const int imm8)
/// VPSHUFD ymm, ymm, ymm/m256
/// VPSHUFD ymm, ymm/m256, imm8
/// </summary>
public static Vector256<uint> Shuffle(Vector256<uint> value, byte control) { throw new PlatformNotSupportedException(); }

Просмотреть файл

@ -407,51 +407,103 @@ namespace System.Runtime.Intrinsics.X86
/// </summary>
public static Vector256<T> BroadcastScalarToVector256<T>(Vector128<T> value) where T : struct => BroadcastScalarToVector256<T>(value);
/// <summary>
/// __m256i _mm256_broadcastb_epi8 (__m128i a)
/// VPBROADCASTB ymm, m8
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<byte> BroadcastScalarToVector256(byte* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastb_epi8 (__m128i a)
/// VPBROADCASTB ymm, m8
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<sbyte> BroadcastScalarToVector256(sbyte* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastw_epi16 (__m128i a)
/// VPBROADCASTW ymm, m16
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<short> BroadcastScalarToVector256(short* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastw_epi16 (__m128i a)
/// VPBROADCASTW ymm, m16
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ushort> BroadcastScalarToVector256(ushort* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastd_epi32 (__m128i a)
/// VPBROADCASTD ymm, m32
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<int> BroadcastScalarToVector256(int* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastd_epi32 (__m128i a)
/// VPBROADCASTD ymm, m32
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<uint> BroadcastScalarToVector256(uint* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastq_epi64 (__m128i a)
/// VPBROADCASTQ ymm, m64
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<long> BroadcastScalarToVector256(long* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastq_epi64 (__m128i a)
/// VPBROADCASTQ ymm, m64
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ulong> BroadcastScalarToVector256(ulong* source) => BroadcastScalarToVector256(source);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m8
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<sbyte> BroadcastVector128ToVector256(sbyte* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m8
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<byte> BroadcastVector128ToVector256(byte* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m16
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<short> BroadcastVector128ToVector256(short* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m16
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ushort> BroadcastVector128ToVector256(ushort* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m32
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<int> BroadcastVector128ToVector256(int* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m32
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<uint> BroadcastVector128ToVector256(uint* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m64
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<long> BroadcastVector128ToVector256(long* address) => BroadcastVector128ToVector256(address);
/// <summary>
/// __m256i _mm256_broadcastsi128_si256 (__m128i a)
/// VBROADCASTI128 xmm, m64
/// VBROADCASTI128 ymm, m128
/// The above native signature does not directly correspond to the managed signature.
/// </summary>
public static unsafe Vector256<ulong> BroadcastVector128ToVector256(ulong* address) => BroadcastVector128ToVector256(address);
@ -2202,17 +2254,17 @@ namespace System.Runtime.Intrinsics.X86
/// <summary>
/// __m256i _mm256_permutevar8x32_epi32 (__m256i a, __m256i idx)
/// VPERMD ymm, ymm/m256, imm8
/// VPERMD ymm, ymm/m256, ymm
/// </summary>
public static Vector256<int> PermuteVar8x32(Vector256<int> left, Vector256<int> control) => PermuteVar8x32(left, control);
/// <summary>
/// __m256i _mm256_permutevar8x32_epi32 (__m256i a, __m256i idx)
/// VPERMD ymm, ymm/m256, imm8
/// VPERMD ymm, ymm/m256, ymm
/// </summary>
public static Vector256<uint> PermuteVar8x32(Vector256<uint> left, Vector256<uint> control) => PermuteVar8x32(left, control);
/// <summary>
/// __m256 _mm256_permutevar8x32_ps (__m256 a, __m256i idx)
/// VPERMPS ymm, ymm/m256, imm8
/// VPERMPS ymm, ymm/m256, ymm
/// </summary>
public static Vector256<float> PermuteVar8x32(Vector256<float> left, Vector256<int> control) => PermuteVar8x32(left, control);
@ -2552,12 +2604,12 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<byte> Shuffle(Vector256<byte> value, Vector256<byte> mask) => Shuffle(value, mask);
/// <summary>
/// __m256i _mm256_shuffle_epi32 (__m256i a, const int imm8)
/// VPSHUFD ymm, ymm, ymm/m256
/// VPSHUFD ymm, ymm/m256, imm8
/// </summary>
public static Vector256<int> Shuffle(Vector256<int> value, byte control) => Shuffle(value, control);
/// <summary>
/// __m256i _mm256_shuffle_epi32 (__m256i a, const int imm8)
/// VPSHUFD ymm, ymm, ymm/m256
/// VPSHUFD ymm, ymm/m256, imm8
/// </summary>
public static Vector256<uint> Shuffle(Vector256<uint> value, byte control) => Shuffle(value, control);

Просмотреть файл

@ -0,0 +1,129 @@
// 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.Runtime.CompilerServices;
using System.Diagnostics;
namespace System.Text
{
internal static partial class Utf16Utility
{
/// <summary>
/// Returns true iff the UInt32 represents two ASCII UTF-16 characters in machine endianness.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool AllCharsInUInt32AreAscii(uint value)
{
return (value & ~0x007F007Fu) == 0;
}
/// <summary>
/// Given a UInt32 that represents two ASCII UTF-16 characters, returns the invariant
/// lowercase representation of those characters. Requires the input value to contain
/// two ASCII UTF-16 characters in machine endianness.
/// </summary>
/// <remarks>
/// This is a branchless implementation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static uint ConvertAllAsciiCharsInUInt32ToLowercase(uint value)
{
// ASSUMPTION: Caller has validated that input value is ASCII.
Debug.Assert(AllCharsInUInt32AreAscii(value));
// the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'A'
uint lowerIndicator = value + 0x00800080u - 0x00410041u;
// the 0x80 bit of each word of 'upperIndicator' will be set iff the word has value <= 'Z'
uint upperIndicator = value + 0x00800080u - 0x005B005Bu;
// the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'A' and <= 'Z'
uint combinedIndicator = (lowerIndicator ^ upperIndicator);
// the 0x20 bit of each word of 'mask' will be set iff the word has value >= 'A' and <= 'Z'
uint mask = (combinedIndicator & 0x00800080u) >> 2;
return value ^ mask; // bit flip uppercase letters [A-Z] => [a-z]
}
/// <summary>
/// Given a UInt32 that represents two ASCII UTF-16 characters, returns the invariant
/// uppercase representation of those characters. Requires the input value to contain
/// two ASCII UTF-16 characters in machine endianness.
/// </summary>
/// <remarks>
/// This is a branchless implementation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static uint ConvertAllAsciiCharsInUInt32ToUppercase(uint value)
{
// ASSUMPTION: Caller has validated that input value is ASCII.
Debug.Assert(AllCharsInUInt32AreAscii(value));
// the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'a'
uint lowerIndicator = value + 0x00800080u - 0x00610061u;
// the 0x80 bit of each word of 'upperIndicator' will be set iff the word has value <= 'z'
uint upperIndicator = value + 0x00800080u - 0x007B007Bu;
// the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'a' and <= 'z'
uint combinedIndicator = (lowerIndicator ^ upperIndicator);
// the 0x20 bit of each word of 'mask' will be set iff the word has value >= 'a' and <= 'z'
uint mask = (combinedIndicator & 0x00800080u) >> 2;
return value ^ mask; // bit flip lowercase letters [a-z] => [A-Z]
}
/// <summary>
/// Given a UInt32 that represents two ASCII UTF-16 characters, returns true iff
/// the input contains one or more lowercase ASCII characters.
/// </summary>
/// <remarks>
/// This is a branchless implementation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool UInt32ContainsAnyLowercaseAsciiChar(uint value)
{
// ASSUMPTION: Caller has validated that input value is ASCII.
Debug.Assert(AllCharsInUInt32AreAscii(value));
// the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'a'
uint lowerIndicator = value + 0x00800080u - 0x00610061u;
// the 0x80 bit of each word of 'upperIndicator' will be set iff the word has value <= 'z'
uint upperIndicator = value + 0x00800080u - 0x007B007Bu;
// the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'a' and <= 'z'
uint combinedIndicator = (lowerIndicator ^ upperIndicator);
return (combinedIndicator & 0x00800080u) != 0;
}
/// <summary>
/// Given a UInt32 that represents two ASCII UTF-16 characters, returns true iff
/// the input contains one or more uppercase ASCII characters.
/// </summary>
/// <remarks>
/// This is a branchless implementation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool UInt32ContainsAnyUppercaseAsciiChar(uint value)
{
// ASSUMPTION: Caller has validated that input value is ASCII.
Debug.Assert(AllCharsInUInt32AreAscii(value));
// the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'A'
uint lowerIndicator = value + 0x00800080u - 0x00410041u;
// the 0x80 bit of each word of 'upperIndicator' will be set iff the word has value <= 'Z'
uint upperIndicator = value + 0x00800080u - 0x005B005Bu;
// the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'A' and <= 'Z'
uint combinedIndicator = (lowerIndicator ^ upperIndicator);
return (combinedIndicator & 0x00800080u) != 0;
}
}
}

Просмотреть файл

@ -342,7 +342,7 @@ namespace System
// For backward-compatibility, we need to special case for the types
// whose UnderlyingSystemType are runtime implemented.
Type toType = this.UnderlyingSystemType;
if (toType.IsRuntimeImplemented())
if (toType?.IsRuntimeImplemented() == true)
return toType.IsAssignableFrom(c);
// If c is a subclass of this class, then c can be cast to this type.

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
#if PLATFORM_WINDOWS
using CpObj;
#endif
@ -314,6 +315,10 @@ internal static class Program
TestConstrainedClassCalls();
TestValueTypeElementIndexing();
TestArrayItfDispatch();
// This test should remain last to get other results before stopping the debugger
PrintLine("Debugger.Break() test: Ok if debugger is open and breaks.");
System.Diagnostics.Debugger.Break();
@ -617,6 +622,34 @@ internal static class Program
return obj.GetHashCode();
}
private static void TestArrayItfDispatch()
{
ICollection<int> arrayItfDispatchTest = new int[37];
PrintString("Array interface dispatch test: ");
if (arrayItfDispatchTest.Count == 37)
{
PrintLine("Ok.");
}
else
{
PrintLine("Failed. asm.js (WASM=1) known to fail due to alignment problem, although this problem sometimes means we don't even get this far and fails with an invalid function pointer.");
}
}
private static void TestValueTypeElementIndexing()
{
var chars = new[] { 'i', 'p', 's', 'u', 'm' };
PrintString("Value type element indexing: ");
if (chars[0] == 'i' && chars[1] == 'p' && chars[2] == 's' && chars[3] == 'u' && chars[4] == 'm')
{
PrintLine("Ok.");
}
else
{
PrintLine("Failed.");
}
}
[DllImport("*")]
private static unsafe extern int printf(byte* str, byte* unused);
}