Skip to content

Commit

Permalink
CoreCLR interpreter basic compilation and execution (#112369)
Browse files Browse the repository at this point in the history
* Interpreter wire up

This commit adds a new library for the interpreter. This library is meant to be used as an alt jit compiler, exporting the `getJit` method that returns an interface for method compilation. This library also exports the `getInterpreter` method that returns a separate interface to be used for obtaining any other data from the interpreter library. Method compilation has the following responsability:
        - create an InterpMethod* for the MethodDesc that it flags as compiled. On mono, InterpMethod serves as reference to the method to be called (which is embedded throughout the code) and later on, following compilation, it is filled with additional information relevant for execution, mainly the code pointer and size of the frame. On CoreCLR, this structure will likely lose some of its relevance, we will end up referencing MethodDesc's directly in interpreter instructions. In the future, it will probably make more sense to have a few common fields of the InterpMethod (like the frame size) stored as a code header to the interpreter IR, with a InterpMethod pointer to be stored as well in the code header for less frequent data.
        - set the CORINFO_FLG_INTERPRETER flag in the MethodDesc. This sets up the method to be called through the InterpreterStub.
        - some dummy data that is necessary by the runtime is being generated, mainly the code

The interpreter execution is included in the main coreclr library for convenience and speed. It will be contained in interpexec.h and interpexec.cpp while also including the interpretershared.h header from the interpreter library. This header will contain any defines and types that are relevant both during compilation as well as execution (for example the InterpMethod data or the opcode values). For the execution, InterpFrame is a structure on the native stack that is created for each interpreter frame. It will reference the method being executed as well as pointers to the interpreter stack. InterpThreadContext is a thread local structure that contains execution relevant information for the interpreter, for now it just maintains the position of the interpreter stack pointer.

* Add support for compilation and execution of a simple method

This commit ports over some of the compilation machinery from mono. Method compilation takes place in GenerateCode. It allocates a basic block, goes over the IL code and emits code as it goes, while updating the IL stack state. Method code is kept as a linked list of basic blocks. Each basic block keeps a linked list of instructions. The instruction information is represented by an opcode, source and destination vars and additional instruction data. Once the IL code is imported, the var offset allocator needs to kick in in order to allocate an offset for each variable referenced in the code. Once offsets are allocated the final interpreter IR can be generated, writing the opcode and instruction data linearly in the code, while replacing variable indexes with the actual variable offset.

Unlike the mono interpreter, that maintains the code as an uint16_t stream, we chose to use from the start an int32_t based stream. The mono interpreter runs into limitations when executing very large methods, where some offsets don't fit in the uint16_t space. There will be a performance penalty for this that will be addressed in the distant future, by adding short versions for common opcodes.

* Add interpreter test

The test contains one application that contains a method named `RunInterpreterTests` serving as the interpreter entry point. This application is built only, as it is not the test itself. This application is executed with corerun by the actual test, which waits for the corerun exit code to determine success.

* Stop using a mapping table between MethodDesc and InterpMethod

InterpMethod* is used to handle interpreted method execution on mono, but it is not really needed. For CoreCLR we will turn this structure in a header to the compiled IR code, and identify other methods directly by the IR code pointer. The first pointer slot in the IR code will contain a pointer to the InterpMethod containing any other relevant information needed in the method execution.
  • Loading branch information
BrzVlad authored Feb 21, 2025
1 parent 1eadeff commit 57ed254
Show file tree
Hide file tree
Showing 22 changed files with 1,410 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/coreclr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ include_directories("${GENERATED_INCLUDE_DIR}")
include_directories("hosts/inc")
include_directories("minipal")

add_subdirectory(interpreter)

if(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
include_directories("${GENERATED_INCLUDE_DIR}/etw")
endif(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
Expand Down
47 changes: 47 additions & 0 deletions src/coreclr/interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(INTERPRETER_SOURCES
compiler.cpp
compileropt.cpp
intops.cpp
eeinterp.cpp)

set(INTERPRETER_LINK_LIBRARIES
)

if(CLR_CMAKE_HOST_WIN32)
list(APPEND INTERPRETER_LINK_LIBRARIES
${STATIC_MT_CRT_LIB}
${STATIC_MT_VCRT_LIB}
)
endif(CLR_CMAKE_HOST_WIN32)

if(CLR_CMAKE_HOST_WIN32)
set(CLRINTERPRETER_EXPORTS ${CMAKE_CURRENT_LIST_DIR}/clrinterpreter.exports)
set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/clrinterpreter.def)
preprocess_file(${CLRINTERPRETER_EXPORTS} ${EXPORTS_FILE})
list(APPEND INTERPRETER_SOURCES ${EXPORTS_FILE})
add_custom_target(interpreter_exports DEPENDS ${EXPORTS_FILE})
else()
set(CLRINTERPRETER_EXPORTS ${CMAKE_CURRENT_LIST_DIR}/clrinterpreter_unixexports.src)
set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/clrinterpreter.exports)
generate_exports_file(${CLRINTERPRETER_EXPORTS} ${EXPORTS_FILE})
add_custom_target(interpreter_exports DEPENDS ${EXPORTS_FILE})
endif()

add_library_clr(clrinterpreter SHARED ${INTERPRETER_SOURCES})

add_dependencies(clrinterpreter interpreter_exports)

if(NOT CLR_CMAKE_HOST_WIN32)
set_exports_linker_option(${EXPORTS_FILE})
set_property(TARGET clrinterpreter APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
endif()

target_link_libraries(clrinterpreter
PRIVATE
${INTERPRETER_LINK_LIBRARIES}
)

set_property(TARGET clrinterpreter APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})

install_clr(TARGETS clrinterpreter DESTINATIONS . COMPONENT runtime)
5 changes: 5 additions & 0 deletions src/coreclr/interpreter/clrinterpreter.exports
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; Licensed to the .NET Foundation under one or more agreements.
; The .NET Foundation licenses this file to you under the MIT license.
EXPORTS
getJit
jitStartup
2 changes: 2 additions & 0 deletions src/coreclr/interpreter/clrinterpreter_unixexports.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
getJit
jitStartup
Loading

0 comments on commit 57ed254

Please sign in to comment.