Fact-checked by Grok 2 weeks ago

Common Intermediate Language

Common Intermediate Language (CIL) is a low-level, platform-independent set of instructions defined within the Common Language Infrastructure (CLI), serving as the intermediate representation for code compiled from high-level languages in the .NET ecosystem. It enables cross-language interoperability and execution on diverse hardware architectures by abstracting away CPU-specific details, functioning as an object-oriented assembly language that is stack-based and includes support for arithmetic operations, control flow, object manipulation, and exception handling. In the .NET managed execution process, compilers for languages such as C# and Visual Basic .NET translate source code into CIL instructions, which are then packaged with metadata into portable executable (PE) files. This metadata describes the types, members, and other elements needed for runtime resolution, ensuring type safety and secure memory access through verification by the Common Language Runtime (CLR). At runtime, the CLR's just-in-time (JIT) compiler converts CIL to native machine code optimized for the host processor, while tools like NGen allow ahead-of-time compilation for improved performance. Standardized by Ecma International as part of ECMA-335 (6th edition, June 2012), CIL forms Partition III of the CLI specification, providing a machine-readable instruction set that supports multiple programming languages and facilitates tools for assembly, disassembly, and analysis. Originally developed by Microsoft as part of the .NET Framework, it underpins both .NET Framework and cross-platform .NET implementations like .NET Core and .NET 5+, promoting language independence and portability across operating systems such as Windows, Linux, and macOS.

Overview

Definition and Purpose

Common Intermediate Language (CIL), also known as Microsoft Intermediate Language (MSIL) or simply IL, is a stack-based, object-oriented assembly language that serves as the intermediate representation for managed code in the .NET ecosystem. It is defined in Partition III of the ECMA-335 standard for the Common Language Infrastructure (CLI), providing a CPU-independent set of instructions that abstract platform-specific details. The primary purpose of CIL is to enable seamless language interoperability within the .NET Framework by allowing compilers for diverse high-level languages, such as C# and VB.NET, to generate a common bytecode form. This bytecode is verified and executed by the Common Language Runtime (CLR), which enforces type safety through runtime checks on CIL instructions, preventing invalid operations and enhancing security. Additionally, CIL integrates with metadata—a structured description of types, members, and assemblies—facilitating reflection and dynamic loading at runtime. CIL code is stored in (PE) files, typically with .exe or .dll extensions, where the CIL instructions occupy a dedicated separate from . This format promotes platform , as the CLR's just-in-time (JIT) translates CIL to native optimized for the host during execution. Unlike opaque , CIL opcodes are human-readable, allowing developers to inspect and debug assemblies using tools like Ildasm.exe, the IL .

History and Development

The development of what would become the Common Intermediate Language (CIL) began in the late 1990s as part of Microsoft's initiative to create a unified platform for software development, initially codenamed Next Generation Windows Services (NGWS). The Common Language Runtime (CLR) team at Microsoft designed the intermediate language, originally termed Microsoft Intermediate Language (MSIL), to serve as a platform-agnostic bytecode format that could support multiple high-level languages while drawing on prior experiences with virtual machine technologies like the Java Virtual Machine. The first beta versions of the .NET Framework, incorporating MSIL, were released in late 2000, with the full .NET Framework 1.0 launching on February 13, 2002, marking the formal introduction of MSIL as the core compilation target for .NET languages. In preparation for broader adoption and interoperability, Microsoft pursued standardization, leading to the renaming of MSIL to CIL to reflect its role in the emerging open specification. The first edition of ECMA-335, defining the Common Language Infrastructure (CLI)—which encompasses CIL—was ratified by Ecma International in December 2001. This was followed by the second edition in December 2002, which refined the CLI architecture and metadata formats, including CIL instructions. The standard was further adopted internationally as ISO/IEC 23271 in 2003, with a second edition in 2006 aligning closely with ECMA updates and incorporating patent commitments from Microsoft. Subsequent ECMA editions, such as the third in June 2005 and the sixth in June 2012, continued to evolve the specification, ensuring CIL's robustness for modern .NET ecosystems. CIL evolved alongside .NET Framework releases to accommodate new language features. The .NET Framework 2.0, released in November 2005, introduced generics support through new CIL opcodes and metadata constructs, enabling type-safe reusable code without runtime overhead, as detailed in the third edition of ECMA-335. Similarly, .NET Framework 4.0 in April 2010 enhanced dynamic capabilities via integration with the Dynamic Language Runtime (DLR), allowing CIL to handle late-bound operations more efficiently for scripting and interop scenarios. In April 2014, Microsoft open-sourced key components of .NET, including the Roslyn compiler, which generates CIL and has since benefited from community contributions refining emission and optimization techniques. The shift to cross-platform development accelerated with .NET Core's initial release in June 2016, maintaining full CIL compatibility while adapting the runtime for Linux and macOS, thus extending CIL's reach beyond Windows. This evolution culminated in the unified .NET 5 platform in November 2020 and beyond, where CIL remains the foundational intermediate format, with ongoing ECMA alignments ensuring backward compatibility and standardization through the 2020s.

Language Structure

Instruction Set

The Common Intermediate Language (CIL) employs a stack-based evaluation model, where instructions manipulate an operand stack to perform computations and control execution flow. In this model, data is pushed onto the stack using load instructions such as ldloc (which loads a value from a local variable onto the stack) and ldarg (which loads an argument), while store instructions like stloc pop values from the stack and assign them to locals or fields. Arithmetic operations, such as add (which pops two values, adds them, and pushes the result), and method invocations via call or callvirt also operate directly on this stack, ensuring a linear flow of data without explicit registers. CIL instructions are categorized into several functional groups to support diverse programming operations. Arithmetic instructions handle numerical computations, including add, sub for subtraction, and mul for multiplication, each popping operands from the stack and pushing the result while enforcing type compatibility. Control flow instructions manage branching and loops, such as unconditional br (branch to a specified offset) and conditional brtrue (branch if the top stack value is true). Load and store instructions facilitate data movement, with examples like ldstr (loading a string constant onto the stack) and ldarg for arguments, alongside stores to locals or fields. Method call instructions enable invocation of code, where call targets static or value-type methods and callvirt supports virtual calls on reference types or interfaces. Opcode encoding in CIL uses compact representations to define operations efficiently. Primary are single-byte values ranging from 0x00 to 0xFF, with specific assignments like 0x58 for add; these may be followed by inline operands, such as 4-byte offsets for targets or type tokens resolved via . To extend the space beyond 256 entries, (e.g., 0xFE) introduce secondary sets, allowing additional operations without conflicting with primary encodings. This balances and extensibility in compiled assemblies. The CIL instruction set comprises over 200 opcodes, providing comprehensive support for computation, with specialized prefixes like constrained for handling generic method calls (ensuring exact type resolution during virtual dispatch) and readonly (introduced in .NET 4.5 to mark contexts where structures are treated immutably, such as in spans or readonly references). These extensions enhance support for modern language features while maintaining backward compatibility. Verification in CIL ensures type safety through rules that track stack transitions at each instruction, enforced by the Common Language Runtime (CLR) verifier prior to execution. For instance, an instruction like add requires the top two stack items to be compatible numeric types (e.g., both int32), popping them and pushing a result of the promoted type; mismatches trigger verification failures. This data-flow analysis confirms that all stack operations preserve type invariants, preventing invalid casts or overflows at runtime.

Metadata Format

The metadata in Common Intermediate Language (CIL) assemblies functions as a key-value store embedded in the assembly headers, providing descriptive information about types, members, and other program elements. It is structured around more than 40 distinct tables, such as TypeDef for type definitions, MethodDef for method definitions, Field for field declarations, and MemberRef for references to members in other assemblies. These tables organize data into rows and columns, enabling the Common Language Runtime (CLR) to resolve and bind program components efficiently. The metadata employs both a logical and a physical format to balance readability and compactness. In its logical form, it uses indexed tables for resolution, where each row can be referenced via metadata tokens—compact identifiers that support type and member lookups during execution. The physical format, stored as a binary layout within Portable Executable (PE) files, includes a metadata root that directs to several streams, accompanied by heaps for supplementary data: the #Strings heap for string literals, the #Blob heap for binary objects like method signatures, the #GUID heap for unique identifiers, and the user strings heap for custom strings. Indices into these heaps begin at 1, with sizes indicated by flags to optimize storage. Signatures in metadata are encoded in a compressed binary form to represent types and structures efficiently, stored primarily in the #Blob heap. For instance, a method signature for void M(int32) is encoded as a sequence beginning with the calling convention, followed by the return type VOID and parameter type INT32, using element type codes and variable-length integers for compactness. This encoding applies similarly to field signatures, local variable declarations, and other constructs, minimizing overhead while preserving necessary details for type safety and interoperability. Such compression ensures that signatures remain succinct even in complex assemblies. Metadata plays a pivotal role in enabling reflection capabilities, such as those provided by the System.Reflection namespace, which allows runtime inspection and manipulation of types and members based on this descriptive data. Its size varies depending on assembly complexity, typically ranging from kilobytes to megabytes and constituting a significant portion of the overall file. During assembly loading, the PE header references the metadata root, which the CLR parses to perform type binding and dependency resolution, ensuring correct program initialization. This structure also supports operands in CIL instructions for referencing external types and members.

Computational Model

Object-Oriented Features

Common Intermediate Language (CIL) supports object-oriented programming through metadata directives and dedicated instructions that enable the definition, instantiation, and manipulation of classes and objects. Instance classes are defined using the .class directive in assembly manifests or IL assembler (ILASM), which specifies the class name, visibility attributes such as public for external accessibility, and sealed to prevent further inheritance, as outlined in the Type Definition (TypeDef) table of the metadata. Inheritance is declared via the extends clause, linking a derived class to its base class, forming a single-inheritance hierarchy typically rooted at System.Object unless otherwise specified. Object creation in CIL occurs via the newobj instruction, which allocates memory for a new instance on the managed heap, initializes it to zero, and immediately invokes the specified constructor to perform any necessary setup, pushing the resulting object reference onto the evaluation stack. For example, newobj instance void MyClass::.ctor() creates an instance of MyClass and calls its parameterless constructor. Method invocation supports polymorphism with the call instruction for static methods or non-virtual instance methods, which performs direct binding, and callvirt for virtual or interface methods, enabling late-bound dispatch based on the actual object type at runtime. The tail. prefix can optimize these calls—such as tail.call or tail.callvirt—by reusing the current stack frame, preventing stack overflow in recursive scenarios and ensuring efficient tail-call elimination. To integrate value types with the object-oriented model, CIL provides boxing and unboxing mechanisms: the box instruction wraps a value type (e.g., int32) into a reference type object on the heap, allowing it to be treated as an instance of System.Object, while unbox extracts the value from such an object, yielding a managed pointer to the unboxed data. For instance, box int32 converts an integer value to an object reference, facilitating operations like passing value types to methods expecting object parameters. Exception handling in CIL employs structured constructs, including .try blocks paired with fault handlers via the .fault directive, which execute cleanup code unconditionally upon any exception exiting the try block but not on normal completion; the leave instruction then provides controlled exits from these protected regions, ensuring finally or fault handlers are invoked as needed. These features collectively enable robust support for encapsulation, inheritance, and polymorphism within the CIL execution model.

Type System and Operations

The Common Intermediate Language (CIL) operates within the framework of the Common Type System (CTS), a unified type system that ensures type compatibility across languages in the Common Language Infrastructure (CLI). The CTS categorizes types into value types and reference types, where value types store their data directly on the stack or inlined within other types, promoting efficiency for small, immutable data, while reference types allocate data on the managed heap and are accessed via pointers, enabling sharing and polymorphism. This distinction supports interoperability by enforcing consistent behavior for assignment, passing, and inheritance, as defined in the CLI specification. CIL includes a set of built-in primitive types that form the foundation for computations, such as int32 (a 32-bit signed integer), float64 (a 64-bit double-precision floating-point number), string (a reference type for immutable sequences of Unicode characters), and object (the base reference type for all other reference types). Value types encompass these primitives along with user-defined structs, which can include fields of other value or reference types but are copied by value during assignment. In contrast, reference types like classes derive from object and support garbage collection, with examples including arrays and delegates. These types are verified at runtime to prevent invalid operations, ensuring type safety. CIL provides a rich set of operations for manipulating these types, primarily through stack-based instructions that load, compute, and store values. Arithmetic operations include add.ovf, which adds two integer values and throws an OverflowException if the result exceeds the type's representable range, alongside unchecked variants like add for performance-critical code. Comparison instructions such as ceq (compares two values for equality, pushing 1 for true or 0 for false) and clt (compares for less than) support both numeric and reference types, with results as int32 on the stack. Type conversions are handled by instructions like conv.i4 (converts the top stack value to a 32-bit signed integer, truncating if necessary) and conv.r8 (converts to a 64-bit floating-point number), which enforce implicit or explicit casting rules from the CTS to avoid data loss where possible. Arrays in CIL are reference types that support single-dimensional, zero-based indexing, with initialization via newarr, which allocates a specified number of elements of a given type on the heap and pushes a reference to the array. Access operations include ldelem (load element), such as ldelem.i4 for loading a 32-bit integer from an array at the index on the stack, while refany provides typed references for safe manipulation of elements without exposing raw pointers. Multidimensional arrays are supported through a rank-based representation, allowing creation with the newarr instruction for single-dimensional arrays or newobj for multidimensional arrays, with stelem for storing values into elements, maintaining type safety across dimensions. Type compatibility is enforced by the CTS through instructions like isinst, which checks if an object reference is an instance of a specified type or its subtype, pushing the reference if true or null if false, enabling dynamic type testing without exceptions. Stack management is handled by instructions such as dup, which duplicates the top value on the evaluation stack for reuse in operations, and pop, which discards the top value, facilitating operand handling in the stack-based execution model without explicit registers. These mechanisms collectively ensure that CIL code remains verifiable and secure during execution.

Code Generation

Compiling Source Code to CIL

The process of compiling source code to Common Intermediate Language (CIL) involves a structured pipeline that transforms high-level language constructs into verifiable intermediate code suitable for the .NET runtime. In the Roslyn compiler, used for both C# and Visual Basic .NET, the pipeline begins with parsing the source code into a syntax tree (analogous to an abstract syntax tree or AST), followed by declaration analysis to build a symbol table from the code and referenced metadata, binding to resolve semantic meaning by matching identifiers to symbols, and finally emission to generate CIL bytecode embedded in a Portable Executable (PE) assembly format. This sequence ensures that the output CIL is metadata-rich and type-safe, with the entire assembly including both the CIL instructions and descriptive metadata for types, methods, and fields. For language-specific mappings, the Roslyn compiler handles C# source code through its C# frontend, producing CIL that adheres to the Common Language Infrastructure (CLI) specifications, while the VB.NET compiler within Roslyn processes Visual Basic .NET syntax similarly, mapping language features like Option Strict to equivalent verifiable CIL constructs. Both compilers enforce verification rules during emission, ensuring the resulting CIL can be executed securely without runtime type safety violations. Dynamic CIL generation bypasses traditional source compilation by using the System.Reflection.Emit namespace, where developers programmatically define types, methods, and emit CIL instructions at runtime to create assemblies on-the-fly, often for scenarios like scripting or just-in-time code creation. Optimizations occur primarily during the binding and emission phases to improve efficiency before CIL output. The compiler performs dead code elimination by analyzing basic blocks and removing unreachable or unused instructions, such as NOPs inserted for debugging, and supports inline expansions for small methods to reduce call overhead when the /optimize flag is enabled. These steps minimize the CIL footprint without altering program semantics, though more aggressive optimizations like loop unrolling are deferred to the runtime JIT compiler. An intermediate validation step using tools such as PEVerify (for .NET Framework) or ILVerify (for .NET Framework and cross-platform .NET) checks the emitted CIL and metadata for compliance with CLI type safety rules; if unverifiable code—such as invalid opcodes or type mismatches—is detected, these tools report errors, and in build configurations enforcing verification (e.g., via MSBuild tasks), compilation halts to prevent deployment of unsafe assemblies. In modern .NET (as of .NET 9), single-file publishing bundles assemblies and dependencies into a single executable, reducing deployment complexity while preserving CIL semantics.

Tools and Emitters

The IL Disassembler (Ildasm.exe) is a command-line tool provided by Microsoft for examining the contents of .NET assemblies, converting the binary portable executable (PE) format into human-readable Common Intermediate Language (CIL) text files with a .il extension. It supports viewing metadata, method bodies, and resources within assemblies, making it essential for reverse-engineering or verifying compiled CIL code. Complementing Ildasm, the IL Assembler (Ilasm.exe) assembles CIL text files back into executable PE files, such as .exe or .dll assemblies, allowing developers to modify or create CIL code manually and then recompile it for testing or deployment. This tool processes directives for metadata and emits the corresponding binary structure, ensuring compatibility with the .NET runtime. For dynamic CIL generation at runtime, the System.Reflection.Emit namespace in .NET provides the ILGenerator class, which uses the OpCodes class to emit individual instructions into method bodies of dynamic assemblies. For instance, to load a string constant onto the stack, code might invoke ILGenerator.Emit(OpCodes.Ldstr, "hello"), enabling scenarios like just-in-time code creation in reflection-based applications. In cross-platform environments, tools from the .NET SDK such as ildasm and ilasm equivalents support inspection and assembly on non-Windows platforms. The .NET CLI, through commands like dotnet build, implicitly generates CIL as part of compiling source code into assemblies, producing intermediate binaries that can then be disassembled or further manipulated using the aforementioned tools. Debugging CIL involves integration with the Visual Studio debugger, where dynamically emitted code can be stepped through if portable PDB symbol files are generated alongside the assembly, allowing breakpoints and variable inspection at the IL level during runtime execution.

Execution and Runtime

Just-In-Time Compilation

Just-in-time (JIT) compilation in the Common Language Runtime (CLR) converts Common Intermediate Language (CIL) bytecode into native machine code at runtime, enabling platform-specific execution while providing services like verification and optimization. The workflow begins with method loading, where the CLR loader creates an initial stub for each method upon type initialization. This is followed by verification, which examines the CIL and associated metadata to ensure type safety, including checks on memory accesses and method calls. Optimization then occurs, applying transformations to improve performance, before the final code generation step, where the JIT compiler translates the verified and optimized CIL into native instructions for the target processor. Since the release of .NET Core 1.0 in 2016, the RyuJIT compiler has been the primary JIT implementation, replacing earlier versions for better performance across x64 and x86 architectures. RyuJIT performs key optimizations such as inlining small methods to reduce call overhead, loop unrolling to minimize iteration control costs, and advanced register allocation to optimize CPU resource usage. Tiered compilation, introduced in .NET Core 3.0 (2019), enhances startup speed by initially generating quick, minimally optimized code (Tier 0) for cold paths, then recompiling hot paths with full optimizations (Tier 1); in .NET 7 and later, this includes support for on-stack replacement (OSR) in methods with loops. In .NET 9 (2024), further JIT enhancements include improved loop optimizations, inlining, and Arm64 code generation. The first invocation of a method triggers its JIT compilation, after which the generated native code is cached in memory for reuse on subsequent calls, avoiding redundant compilation. This process distinguishes cold paths, which receive basic compilation for rapid execution, from hot paths, which undergo tiered JIT for deeper optimizations based on runtime profiling. RyuJIT supports platforms including x86 and ARM64, generating architecture-specific code, and translates managed exception handling constructs into operating system semantics, such as structured exception handling (SEH) on Windows. For garbage collection integration, the JIT emits GC-safe code by inserting polls at method prologs, loop headers, and other safe points, allowing the collector to pause execution cooperatively without corrupting the stack or registers.

Ahead-of-Time Compilation

Ahead-of-Time (AOT) compilation in the context of Common Intermediate Language (CIL) involves pre-compiling entire assemblies into native machine code prior to execution, contrasting with runtime JIT compilation. The process begins with a full scan of the assembly's CIL instructions to generate a native image, which contains processor-specific code optimized for the target platform. In the .NET Framework, this is achieved using Ngen.exe, introduced in .NET Framework 1.0 (2002), which compiles the CIL and installs the resulting native image into the native image cache. For .NET Core and later, CoreCLR employs ReadyToRun (R2R) as a partial AOT approach, pre-compiling frequently used methods to reduce JIT workload while allowing dynamic compilation for less common code paths. Native AOT, which compiles entire applications to native code without requiring a JIT at runtime, was introduced in .NET 7 (2022) via Crossgen2, enabling cross-platform native image generation; in .NET 9, enhancements improve trimming and app size reduction. This technique offers key benefits such as faster application startup times and elimination of JIT compilation overhead during initial execution, making it suitable for scenarios like mobile applications or high-load servers where quick launch is critical. However, it comes with limitations, including larger binary sizes due to the inclusion of pre-compiled code for all methods and potentially reduced optimization levels, as the compiler relies on static analysis without runtime profiling data. It is notably used in Blazor WebAssembly to compile .NET code directly into WebAssembly for browser execution. Deployment of native images typically occurs in the Global Assembly Cache (GAC) for shared use across applications or app-local for isolated scenarios, enhancing load performance in multi-application environments. Upon assembly updates, such as security patches, native images are invalidated to prevent mismatches, requiring regeneration via tools like Ngen.exe's update action to maintain integrity. To mitigate size increases, trimming with ILLinker is applied before AOT, analyzing the CIL to remove unused code paths and dependencies, which is particularly effective for self-contained deployments.

Advanced Features

Pointer and Unmanaged Instructions

The Common Intermediate Language (CIL) provides a set of instructions for manipulating unmanaged pointers, which reference memory outside the managed heap, enabling low-level operations essential for system programming and interoperability with native code. Unmanaged pointers are denoted using the *T syntax, where T is a type such as int32 or void, representing a typed reference to a location in unmanaged memory. These pointers are distinct from managed references, as they do not participate in garbage collection and require explicit management to avoid issues like dangling references. Key instructions for loading and storing values through unmanaged pointers include the indirect load operations (ldind.*), such as ldind.i4 for loading a 32-bit signed integer from the memory location pointed to by the top stack value, and indirect store operations (stind.*), like stind.r8 for storing a 64-bit floating-point value. These opcodes treat the pointer as an address and perform the access without bounds checking, respecting the platform's natural alignment rules—for instance, ldind.u1 allows byte-level access without alignment padding. Conversion instructions like conv.i transform managed values to native integer pointers (equivalent to IntPtr), facilitating arithmetic on addresses. Additionally, the sizeof instruction computes the size in bytes of a specified type, aiding in memory allocation and pointer arithmetic for unmanaged blocks. To ensure stability during unmanaged access, the fixed statement in languages like C# pins managed objects in place, preventing garbage collector movement; this compiles to CIL sequences using constrained prefixes or local variable initialization to establish fixed pointers. Such code requires an "unsafe" context, enabled via compiler options like /unsafe in C#, and is commonly used for platform invoke (P/Invoke) calls to native DLLs, where CIL marshals data between managed and unmanaged realms. However, verification of type safety is intentionally skipped for unsafe code paths, exposing programs to risks such as buffer overflows or memory corruption if pointers are mishandled. These pointer instructions build on value type semantics for efficient in-place operations but emphasize explicit control over memory lifetimes.

Interoperability Extensions

C++/CLI provides specific language extensions that enhance the Common Intermediate Language (CIL) for interoperability between managed .NET code and unmanaged native code, enabling seamless integration in mixed-mode scenarios. These extensions allow developers to declare references to managed objects using tracking handles denoted by the ^ symbol, which act as safe, garbage-collector-aware pointers to entire managed objects on the heap. For finer-grained access within managed objects, interior pointers are declared with the % symbol, permitting operations on members without pinning the entire object, though they require careful handling to avoid garbage collection disruptions. To facilitate references from unmanaged native code to managed objects, the gcroot template from the vcclr.h header wraps a virtual handle, embedding it directly in native types and ensuring automatic cleanup upon scope exit. This is particularly useful for bridging legacy C++ code with .NET components without exposing raw managed pointers. Complementing this, auto_gcroot from the msclr namespace provides RAII-style management for gcroot instances, automatically releasing the held reference when the object goes out of scope, thus preventing memory leaks in mixed environments. Mixed-mode assemblies, compiled using the /clr compiler flag, generate CIL code interspersed with native stubs, allowing a single DLL to contain both managed and unmanaged instructions for direct calls without explicit marshaling overhead. This "It Just Works" (IJW) mechanism in C++/CLI enables transparent invocation between native functions and managed methods, leveraging the runtime's loader to resolve transitions efficiently. Introduced with Visual C++ 2005 as part of the .NET Framework 2.0 (codename Whidbey), these features support ref classes (managed reference types), value classes (managed value types), and interfaces tailored for COM interoperability, facilitating the exposure of .NET components as COM objects or vice versa. For safe access to managed data from unmanaged code, pinning and marshaling extensions include interior pointers (interior_ptr) that point to fields within garbage-collected objects without relocating them during collection, and pinning pointers (pin_ptr) that temporarily fix an object's location in memory to allow direct native manipulation. The pin_ptr keyword creates an interior pointer that inhibits garbage collector movement for its lifetime, typically scoped to locals to minimize pinning duration and reduce performance impacts. auto_gcroot further aids marshaling by providing a scoped holder for managed references in native contexts, ensuring safe transfer without manual pinning in many cases. These mechanisms build on basic CIL pointer instructions like ldind and stind for low-level operations but extend them with language-level safety. As of Visual Studio 2022 version 17.7 (May 2023), initial support for C++20 features has been added to C++/CLI projects to aid maintenance of existing codebases. Although still supported for compatibility with .NET Framework applications on Windows, C++/CLI is not recommended for new development, particularly for Universal Windows Platform (UWP) apps, where C++/WinRT—a header-only library—is preferred for bridging to the Windows Runtime without managed code dependencies. Despite their utility, C++/CLI interoperability extensions are limited to Windows platforms, as they rely on the full .NET runtime and Visual C++ toolchain, precluding cross-platform deployment on Linux or macOS.

References

  1. [1]
    Managed Execution Process - .NET - Microsoft Learn
    Apr 20, 2024 · Compiling translates your source code into common intermediate language (CIL) and generates the required metadata. Compiling CIL to native code.
  2. [2]
    ECMA-335 - Ecma International
    Common Language Infrastructure (CLI) - Defines the infrastructure in which applications written in multiple high-level languages can be executed.
  3. [3]
  4. [4]
    Ngen.exe (Native Image Generator) - .NET Framework
    Oct 26, 2022 · Ngen.exe creates native images, which are files containing compiled processor-specific machine code, and installs them into the native image ...
  5. [5]
    Metadata and Self-Describing Components - .NET | Microsoft Learn
    Apr 20, 2024 · Once loaded, the runtime performs extensive analysis of the method's common intermediate language (CIL) stream to convert it to fast native ...
  6. [6]
    Ildasm.exe (IL Disassembler) - .NET Framework - Microsoft Learn
    Ildasm.exe takes a portable executable (PE) file that contains intermediate language (IL) code and creates a text file suitable as input to Ilasm.exe.Missing: human- | Show results with:human-
  7. [7]
    Intermediate Language - an overview | ScienceDirect Topics
    Work on the system that became the Common Language Infrastructure (CLI) began at Microsoft Corporation in the late 1990s, and was able to benefit from ...<|control11|><|separator|>
  8. [8]
    A Brief History of .NET Framework - SoftTeco
    Jul 1, 2024 · The first beta versions of the .NET framework were released in the late 2000s and on February 13, 2002, the first version .NET 1.0 was released.
  9. [9]
    ISO/IEC 23271:2003 - Common Language Infrastructure
    ISO/IEC 23271:2003 defines the Common Language Infrastructure (CLI) in which applications written in multiple high-level languages may be executed in ...
  10. [10]
    [PDF] Common Language Infrastructure (CLI) Partitions I to VI
    This third edition cancels and replaces the second edition, ECMA 335:2002. Major changes from the previous edition include: •. Added support for generic ...
  11. [11]
    Microsoft Makes 'Roslyn' Compiler Open Source
    Apr 3, 2014 · The Foundation kicks off with 24 .NET Framework open source projects, including Roslyn. Other projects on that list include: Entity Framework ...Missing: CIL | Show results with:CIL
  12. [12]
    Ecma standards for .NET - Microsoft Learn
    The C# Language and the Common Language Infrastructure (CLI) specifications are standardized through Ecma International®.
  13. [13]
    [PDF] ECMA-335, 6th edition, June 2012
    ECMA-335, 6th edition, June 2012, defines Common Language Infrastructure (CLI) Partitions I to VI, including concepts, metadata, instruction set, profiles, and ...
  14. [14]
  15. [15]
  16. [16]
    [PDF] ECMA-335, 5th edition, December 2010
    This International Standard defines the Common Language Infrastructure (CLI) ... Partition III: CIL Instruction Set – Describes the Common Intermediate Language ( ...
  17. [17]
    Common Type System - .NET - Microsoft Learn
    Jan 3, 2024 · In addition to including the property itself, the common intermediate language (CIL) for a type that contains a readable property includes a ...
  18. [18]
    .NET Compiler Platform SDK concepts and object model - C#
    Sep 15, 2021 · Understand the .NET Compiler Platform SDK model · steps of the compiler pipeline processing source code to object code · compiler pipeline api ...Missing: CIL | Show results with:CIL
  19. [19]
    The Roslyn .NET compiler provides C# and Visual Basic ... - GitHub
    Roslyn is the open-source implementation of both the C# and Visual Basic compilers with an API surface for building code analysis tools.Issues · Discussions · Workflow runs · Pull requests
  20. [20]
    Emitting Dynamic Methods and Assemblies - .NET | Microsoft Learn
    Emit namespace that allow a compiler or tool to emit metadata and common intermediate language (CIL) at run time and optionally generate a portable executable ( ...
  21. [21]
    Peverify.exe (PEVerify Tool) - .NET Framework - Microsoft Learn
    The PEVerify tool helps developers who generate Microsoft intermediate language (MSIL) (such as compiler writers and script engine developers)Missing: CIL | Show results with:CIL
  22. [22]
    dotnet/ILMerge: ILMerge is a static linker for .NET Assemblies. - GitHub
    Mar 19, 2021 · ILMerge is a utility that merges multiple .NET assemblies into a single assembly. It is freely available for use and is available as a NuGet package.
  23. [23]
    How to: View assembly contents - .NET - Microsoft Learn
    Apr 20, 2024 · You can use the Ildasm.exe (IL Disassembler) to view common intermediate language (CIL) information in a file. If the file being examined is ...
  24. [24]
    Ilasm.exe (IL Assembler) - .NET Framework - Microsoft Learn
    Jul 23, 2022 · Get started with Ilasm.exe, the IL Assembler. This tool generates a portable executable (PE) file from intermediate language (IL) assembly.Missing: human- | Show results with:human-
  25. [25]
    ILGenerator Class (System.Reflection.Emit) | Microsoft Learn
    ILGenerator is used to generate method bodies for methods and constructors in dynamic assemblies (represented by the MethodBuilder and ConstructorBuilder ...Definition · Remarks
  26. [26]
    ILGenerator.Emit Method (System.Reflection.Emit) | Microsoft Learn
    Overloads ; Emit(OpCode, SByte). Puts the specified instruction and character argument onto the Microsoft intermediate language (MSIL) stream of instructions.
  27. [27]
    OpCodes Class (System.Reflection.Emit) | Microsoft Learn
    Provides field representations of the Microsoft Intermediate Language (MSIL) instructions for emission by the ILGenerator class members (such as Emit(OpCode)).
  28. [28]
    dotnet build command - .NET CLI | Microsoft Learn
    The dotnet build command builds the project, solution, or file-based app and its dependencies into a set of binaries. The binaries include the project's code in ...Dotnet publish · Dotnet run · Dotnet Restore · Dotnet clean
  29. [29]
    Overview of the debugger - Visual Studio (Windows) - Microsoft Learn
    The debugger provides many ways to see what your code is doing while it runs. You can step through your code and look at the values stored in variables.Missing: CIL | Show results with:CIL
  30. [30]
    Performance Improvements in RyuJIT in .NET Core and .NET ...
    Jun 29, 2017 · RyuJIT is the just-in-time compiler used by .NET Core on x64 and now x86 and by the .NET Framework on x64 to compile MSIL bytecode to native ...Missing: workflow | Show results with:workflow
  31. [31]
    JIT optimization: loop unrolling #8107 - dotnet/runtime - GitHub
    May 15, 2017 · I'm creating tracking issues for some optimizations that RyuJit doesn't perform, so we'll have a place to reference/note when we see the ...
  32. [32]
    Performance Improvements in .NET 7 - Microsoft Developer Blogs
    Aug 31, 2022 · NET 7 is fast. Really fast. This post deep-dives into hundreds of performance improvements that contributed to that reality.
  33. [33]
  34. [34]
    ReadyToRun deployment overview - .NET - Microsoft Learn
    Jun 29, 2022 · R2R is a form of ahead-of-time (AOT) compilation. R2R binaries improve startup performance by reducing the amount of work the just-in-time (JIT) ...
  35. [35]
    Native AOT deployment overview - .NET | Microsoft Learn
    Limitations of Native AOT deployment · No dynamic loading, for example, Assembly. · No run-time code generation, for example, System. · No C++/CLI. · Windows: No ...
  36. [36]
    Conversation about crossgen2 - .NET Blog
    Apr 22, 2021 · For example, to enable the native AOT form factor? Simon: Yes – much of the current Crossgen2 code is shared with the NativeAOT project which ...
  37. [37]
    ASP.NET Core Blazor WebAssembly build tools and ahead-of-time ...
    Blazor WebAssembly supports ahead-of-time (AOT) compilation, where you can compile your .NET code directly into WebAssembly. AOT compilation results in runtime ...NET WebAssembly build tools · Ahead-of-time (AOT) compilation
  38. [38]
    Prepare .NET libraries for trimming - Microsoft Learn
    Nov 12, 2024 · The .NET SDK makes it possible to reduce the size of self-contained apps by trimming. Trimming removes unused code from the app and its dependencies.Missing: ILLinker CIL
  39. [39]
    [PDF] C++/CLI Language Specification - Ecma International
    Common Intermediate Language, the instruction set of the Virtual Execution System. ... The primitive types—such as int, double, and bool—are, in fact ...
  40. [40]
    interior_ptr (C++/CLI) - Microsoft Learn
    Aug 3, 2021 · An interior_ptr represents a superset of the functionality of a native pointer. Therefore, anything that can be assigned to a native pointer can ...
  41. [41]
    How to: Declare Handles in Native Types - Microsoft Learn
    Aug 3, 2021 · vcclr.h provides the type-safe wrapper template gcroot to refer to a CLR object from the C++ heap. This template lets you embed a virtual handle ...
  42. [42]
    auto_gcroot Class | Microsoft Learn
    Jun 25, 2025 · If _right is an auto_gcroot , it releases ownership of its object before the object is attached to the current auto_gcroot . Example. C++. Copy.
  43. [43]
    Mixed (Native and Managed) Assemblies - Microsoft Learn
    Aug 3, 2021 · Mixed assemblies are capable of containing both unmanaged machine instructions and MSIL instructions. This allows them to call and be called by .NET components.
  44. [44]
    Integrate Windows Forms and MFC Applications Through C++ Interop
    This article discusses: How C++ interop works; When to use C++ interop in your projects; Using Windows Forms controls in MFC apps; Moving from Windows Forms ...
  45. [45]
    Faster Code with the Modern Language Features of Visual C++ 2005
    Oct 11, 2019 · This article discusses: .NET C++/CLI syntax; Interop technologies; Profile Guided Optimization; MSIL optimization; OpenMP support; Enhanced ...<|separator|>
  46. [46]
    pin_ptr (C++/CLI) - Microsoft Learn
    Jun 9, 2025 · A pinning pointer is an interior pointer that prevents the object pointed to from moving on the garbage-collected heap.
  47. [47]
    Will CoreCLR support C++/CLI crossplat? · Issue #4121 - GitHub
    Apr 7, 2015 · It seems clear that C++/CLI will not be supported cross platform. So, I think what C++/CLI developers need is tool that allows us from ...Missing: WinRT | Show results with:WinRT