Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jim Hogg 2015-03-16 10:57:40 -07:00
Родитель 26a91d3be6 f6100e53ba
Коммит e695c16e6f
143 изменённых файлов: 1061659 добавлений и 301400 удалений

1
.clang-format Normal file
Просмотреть файл

@ -0,0 +1 @@
BasedOnStyle: LLVM

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

@ -23,14 +23,13 @@ class LLILCJitContext;
namespace llvm {
/// \brief Memory manager for LLILC
///
///
/// This class extends \p RTDyldMemoryManager to obtain memory from the
/// CoreCLR's EE for the persistent jit outputs (code, data, and unwind
/// CoreCLR's EE for the persistent jit outputs (code, data, and unwind
/// information). Each jit request instantiates its own memory manager.
class EEMemoryManager : public RTDyldMemoryManager {
public:
/// Construct a new \p EEMemoryManager
/// \param C Jit context for the method being jitted.
EEMemoryManager(LLILCJitContext *C)
@ -48,7 +47,7 @@ public:
///
/// \param Size Size of allocation request in bytes
/// \param Alignment Alignment demand for the allocation
/// \param SectionID SectionID for this particular section of code
/// \param SectionID SectionID for this particular section of code
/// \param SectionName Name of the section
/// \returns Pointer to the newly allocated memory region
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
@ -63,7 +62,7 @@ public:
///
/// \param Size Size of allocation request in bytes
/// \param Alignment Alignment demand for the allocation
/// \param SectionID SectionID for this particular section of code
/// \param SectionID SectionID for this particular section of code
/// \param SectionName Name of the section
/// \param IsReadOnly True if this is intended for read-only data
/// \returns Pointer to the newly allocated memory region
@ -112,7 +111,7 @@ public:
/// \param Addr The address of the data in the pre-loaded image
/// \param LoadAddr The address the data will have once loaded
/// \param Size Size of the unwind data in bytes
/// \note Because we're not relocating data during loading, \p Addr and
/// \note Because we're not relocating data during loading, \p Addr and
/// \p LoadAddr are currently identical.
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override;

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

@ -26,12 +26,12 @@ struct LLILCJitPerThreadState;
/// \brief This struct holds per-jit request state.
///
/// LLILC is invoked to jit one method at a time. An \p LLILCJitContext
/// LLILC is invoked to jit one method at a time. An \p LLILCJitContext
/// represents all of the information about a particular jit request.
///
/// Note the Jit can be re-entered on the same thread thread while in the
/// Note the Jit can be re-entered on the same thread thread while in the
/// middle of jitting a method, if other methods must be run and also require
/// jitting. To handle this, the contexts form a stack, so that the jit can
/// jitting. To handle this, the contexts form a stack, so that the jit can
/// keep the state from nested jit requests distinct from parent requests.
struct LLILCJitContext {
@ -44,15 +44,15 @@ struct LLILCJitContext {
/// \brief Create or sideload the module for this method.
///
/// In typical usage this creates a new empty \p Module to hold the method
/// In typical usage this creates a new empty \p Module to hold the method
/// that is about to be jitted. The reader then creates the IR for the
/// method.
///
/// Alternatively, if BITCODE_PATH is set to a directory name and there is a
/// suitably named bitcode file in that directory, the file is loaded and
/// parsed and the resulting module is returned, and the code from that
/// Alternatively, if BITCODE_PATH is set to a directory name and there is a
/// suitably named bitcode file in that directory, the file is loaded and
/// parsed and the resulting module is returned, and the code from that
/// parsing is used for the method instead. This provides a way to experiment
/// with alternative codegen. Note however jit codegen may embed handle
/// with alternative codegen. Note however jit codegen may embed handle
/// values in the IR and these values can vary from run to run, so a bitcode
/// file saved from a previous run may not work as expected.
///
@ -64,45 +64,44 @@ struct LLILCJitContext {
void outputDebugMethodName();
public:
/// \name CoreCLR EE information
//@{
ICorJitInfo *JitInfo; ///< EE callback interface
CORINFO_METHOD_INFO *MethodInfo; ///< Description of method to jit
uint32_t Flags; ///< Flags controlling jit behavior
CORINFO_EE_INFO EEInfo; ///< Information about internal EE data
std::string MethodName; ///< Name of the method (for diagnostics)
ICorJitInfo *JitInfo; ///< EE callback interface
CORINFO_METHOD_INFO *MethodInfo; ///< Description of method to jit
uint32_t Flags; ///< Flags controlling jit behavior
CORINFO_EE_INFO EEInfo; ///< Information about internal EE data
std::string MethodName; ///< Name of the method (for diagnostics)
//@}
/// \name LLVM information
//@{
llvm::LLVMContext *LLVMContext; ///< LLVM context for types and similar
llvm::Module *CurrentModule; ///< Module holding LLVM IR
llvm::ExecutionEngine *EE; ///< MCJIT execution engine
bool HasLoadedBitCode; ///< Flag for side-loaded LLVM IR
llvm::LLVMContext *LLVMContext; ///< LLVM context for types and similar
llvm::Module *CurrentModule; ///< Module holding LLVM IR
llvm::ExecutionEngine *EE; ///< MCJIT execution engine
bool HasLoadedBitCode; ///< Flag for side-loaded LLVM IR
//@}
/// \name Context management
//@{
LLILCJitContext *Next; ///< Parent jit context, if any
LLILCJitPerThreadState *State; ///< Per thread state for the jit
LLILCJitContext *Next; ///< Parent jit context, if any
LLILCJitPerThreadState *State; ///< Per thread state for the jit
//@}
/// \name Jit output sizes
//@{
uint32_t HotCodeSize = 0; ///< Size of hot code section in bytes
uint32_t ColdCodeSize = 0; ///< Size of cold code section in bytes
uint32_t ReadOnlyDataSize = 0; ///< Size of readonly data ref'd from code
uint32_t HotCodeSize = 0; ///< Size of hot code section in bytes
uint32_t ColdCodeSize = 0; ///< Size of cold code section in bytes
uint32_t ReadOnlyDataSize = 0; ///< Size of readonly data ref'd from code
//@}
};
/// \brief This struct holds per-thread Jit state.
///
/// The Jit may be invoked concurrently on more than one thread. To avoid
/// The Jit may be invoked concurrently on more than one thread. To avoid
/// synchronization overhead it maintains per-thread state, mainly to map from
/// CoreCLR EE artifacts to LLVM data structures.
///
/// The per thread state also provides access to the current Jit context in
/// The per thread state also provides access to the current Jit context in
/// case it is ever needed.
struct LLILCJitPerThreadState {
public:
@ -124,13 +123,13 @@ public:
/// \brief Map from class handles for arrays to the LLVM types that represent
/// them.
///
/// \note Arrays can't be looked up via the \p ClassTypeMap. Instead they
/// \note Arrays can't be looked up via the \p ClassTypeMap. Instead they
/// are looked up via element type, element handle, and array rank.
std::map<std::tuple<CorInfoType, CORINFO_CLASS_HANDLE, uint32_t>,
llvm::Type *> ArrayTypeMap;
/// \brief Map from a field handle to the index of that field in the overall
/// layout of the enclosing class.
/// layout of the enclosing class.
///
/// Used to build struct GEP instructions in LLVM IR for field accesses.
std::map<CORINFO_FIELD_HANDLE, uint32_t> FieldIndexMap;
@ -148,7 +147,6 @@ public:
/// top-level invocations of the jit is held in thread local storage.
class LLILCJit : public ICorJitCompiler {
public:
/// \brief Construct a new jit instance.
///
/// There is only one LLILC jit instance per process, so this
@ -204,7 +202,6 @@ public:
static void signalHandler(void *Cookie);
private:
/// Convert a method into LLVM IR.
/// \param JitContext Context record for the method's jit request.
/// \returns \p true if the conversion was successful.
@ -216,12 +213,10 @@ private:
bool outputGCInfo(LLILCJitContext *JitContext);
public:
/// A pointer to the singleton jit instance.
static LLILCJit *TheJit;
private:
/// Thread local storage for the jit's per-thread state.
llvm::sys::ThreadLocal<LLILCJitPerThreadState> State;
};

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

@ -19,7 +19,7 @@
//
// __stdcall is X86 specific. MSVC ignores the attribute on other architectures,
// whereas other compilers complain about the ignored attribute.
#if !defined(_MSC_VER) && !defined(_HOST_X86_)
#if (!defined(_MSC_VER) || defined(__clang__)) && !defined(_HOST_X86_)
#define __stdcall
#endif // MSC_VER && _HOST_X86
@ -31,6 +31,8 @@
#endif
#include "staticcontract.h"
// clang-format off
// Note: PAL_SEH_RESTORE_GUARD_PAGE is only ever defined in clrex.h, so we only
// restore guard pages automatically when these macros are used from within the
// VM.
@ -776,3 +778,5 @@ struct tagVARIANT {
#endif // _MSC_VER
#endif // LLILC_PAL
// clang-format on

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

@ -0,0 +1,188 @@
//===------------ include/Reader/bytecodetowvmcode.def ----------*- C++ -*-===//
//
// LLILC
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
// See LICENSE file in the project root for full license information.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Declares array for reader.cpp
///
//===----------------------------------------------------------------------===//
// Array which maps bytecode to WVM opcode
static const ReaderBaseNS::OPCODE ByteCodes[256] = {
ReaderBaseNS::CEE_NOP, ReaderBaseNS::CEE_BREAK,
ReaderBaseNS::CEE_LDARG_0, ReaderBaseNS::CEE_LDARG_1,
ReaderBaseNS::CEE_LDARG_2, ReaderBaseNS::CEE_LDARG_3,
ReaderBaseNS::CEE_LDLOC_0, ReaderBaseNS::CEE_LDLOC_1,
ReaderBaseNS::CEE_LDLOC_2, ReaderBaseNS::CEE_LDLOC_3,
ReaderBaseNS::CEE_STLOC_0, ReaderBaseNS::CEE_STLOC_1,
ReaderBaseNS::CEE_STLOC_2, ReaderBaseNS::CEE_STLOC_3,
ReaderBaseNS::CEE_LDARG_S, ReaderBaseNS::CEE_LDARGA_S,
ReaderBaseNS::CEE_STARG_S, ReaderBaseNS::CEE_LDLOC_S,
ReaderBaseNS::CEE_LDLOCA_S, ReaderBaseNS::CEE_STLOC_S,
ReaderBaseNS::CEE_LDNULL, ReaderBaseNS::CEE_LDC_I4_M1,
ReaderBaseNS::CEE_LDC_I4_0, ReaderBaseNS::CEE_LDC_I4_1,
ReaderBaseNS::CEE_LDC_I4_2, ReaderBaseNS::CEE_LDC_I4_3,
ReaderBaseNS::CEE_LDC_I4_4, ReaderBaseNS::CEE_LDC_I4_5,
ReaderBaseNS::CEE_LDC_I4_6, ReaderBaseNS::CEE_LDC_I4_7,
ReaderBaseNS::CEE_LDC_I4_8, ReaderBaseNS::CEE_LDC_I4_S,
ReaderBaseNS::CEE_LDC_I4, ReaderBaseNS::CEE_LDC_I8,
ReaderBaseNS::CEE_LDC_R4, ReaderBaseNS::CEE_LDC_R8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED49,
ReaderBaseNS::CEE_DUP, ReaderBaseNS::CEE_POP,
ReaderBaseNS::CEE_JMP, ReaderBaseNS::CEE_CALL,
ReaderBaseNS::CEE_CALLI, ReaderBaseNS::CEE_RET,
ReaderBaseNS::CEE_BR_S, ReaderBaseNS::CEE_BRFALSE_S,
ReaderBaseNS::CEE_BRTRUE_S, ReaderBaseNS::CEE_BEQ_S,
ReaderBaseNS::CEE_BGE_S, ReaderBaseNS::CEE_BGT_S,
ReaderBaseNS::CEE_BLE_S, ReaderBaseNS::CEE_BLT_S,
ReaderBaseNS::CEE_BNE_UN_S, ReaderBaseNS::CEE_BGE_UN_S,
ReaderBaseNS::CEE_BGT_UN_S, ReaderBaseNS::CEE_BLE_UN_S,
ReaderBaseNS::CEE_BLT_UN_S, ReaderBaseNS::CEE_BR,
ReaderBaseNS::CEE_BRFALSE, ReaderBaseNS::CEE_BRTRUE,
ReaderBaseNS::CEE_BEQ, ReaderBaseNS::CEE_BGE,
ReaderBaseNS::CEE_BGT, ReaderBaseNS::CEE_BLE,
ReaderBaseNS::CEE_BLT, ReaderBaseNS::CEE_BNE_UN,
ReaderBaseNS::CEE_BGE_UN, ReaderBaseNS::CEE_BGT_UN,
ReaderBaseNS::CEE_BLE_UN, ReaderBaseNS::CEE_BLT_UN,
ReaderBaseNS::CEE_SWITCH, ReaderBaseNS::CEE_LDIND_I1,
ReaderBaseNS::CEE_LDIND_U1, ReaderBaseNS::CEE_LDIND_I2,
ReaderBaseNS::CEE_LDIND_U2, ReaderBaseNS::CEE_LDIND_I4,
ReaderBaseNS::CEE_LDIND_U4, ReaderBaseNS::CEE_LDIND_I8,
ReaderBaseNS::CEE_LDIND_I, ReaderBaseNS::CEE_LDIND_R4,
ReaderBaseNS::CEE_LDIND_R8, ReaderBaseNS::CEE_LDIND_REF,
ReaderBaseNS::CEE_STIND_REF, ReaderBaseNS::CEE_STIND_I1,
ReaderBaseNS::CEE_STIND_I2, ReaderBaseNS::CEE_STIND_I4,
ReaderBaseNS::CEE_STIND_I8, ReaderBaseNS::CEE_STIND_R4,
ReaderBaseNS::CEE_STIND_R8, ReaderBaseNS::CEE_ADD,
ReaderBaseNS::CEE_SUB, ReaderBaseNS::CEE_MUL,
ReaderBaseNS::CEE_DIV, ReaderBaseNS::CEE_DIV_UN,
ReaderBaseNS::CEE_REM, ReaderBaseNS::CEE_REM_UN,
ReaderBaseNS::CEE_AND, ReaderBaseNS::CEE_OR,
ReaderBaseNS::CEE_XOR, ReaderBaseNS::CEE_SHL,
ReaderBaseNS::CEE_SHR, ReaderBaseNS::CEE_SHR_UN,
ReaderBaseNS::CEE_NEG, ReaderBaseNS::CEE_NOT,
ReaderBaseNS::CEE_CONV_I1, ReaderBaseNS::CEE_CONV_I2,
ReaderBaseNS::CEE_CONV_I4, ReaderBaseNS::CEE_CONV_I8,
ReaderBaseNS::CEE_CONV_R4, ReaderBaseNS::CEE_CONV_R8,
ReaderBaseNS::CEE_CONV_U4, ReaderBaseNS::CEE_CONV_U8,
ReaderBaseNS::CEE_CALLVIRT, ReaderBaseNS::CEE_CPOBJ,
ReaderBaseNS::CEE_LDOBJ, ReaderBaseNS::CEE_LDSTR,
ReaderBaseNS::CEE_NEWOBJ, ReaderBaseNS::CEE_CASTCLASS,
ReaderBaseNS::CEE_ISINST, ReaderBaseNS::CEE_CONV_R_UN,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED58,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED1,
ReaderBaseNS::CEE_UNBOX, ReaderBaseNS::CEE_THROW,
ReaderBaseNS::CEE_LDFLD, ReaderBaseNS::CEE_LDFLDA,
ReaderBaseNS::CEE_STFLD, ReaderBaseNS::CEE_LDSFLD,
ReaderBaseNS::CEE_LDSFLDA, ReaderBaseNS::CEE_STSFLD,
ReaderBaseNS::CEE_STOBJ, ReaderBaseNS::CEE_CONV_OVF_I1_UN,
ReaderBaseNS::CEE_CONV_OVF_I2_UN, ReaderBaseNS::CEE_CONV_OVF_I4_UN,
ReaderBaseNS::CEE_CONV_OVF_I8_UN, ReaderBaseNS::CEE_CONV_OVF_U1_UN,
ReaderBaseNS::CEE_CONV_OVF_U2_UN, ReaderBaseNS::CEE_CONV_OVF_U4_UN,
ReaderBaseNS::CEE_CONV_OVF_U8_UN, ReaderBaseNS::CEE_CONV_OVF_I_UN,
ReaderBaseNS::CEE_CONV_OVF_U_UN, ReaderBaseNS::CEE_BOX,
ReaderBaseNS::CEE_NEWARR, ReaderBaseNS::CEE_LDLEN,
ReaderBaseNS::CEE_LDELEMA, ReaderBaseNS::CEE_LDELEM_I1,
ReaderBaseNS::CEE_LDELEM_U1, ReaderBaseNS::CEE_LDELEM_I2,
ReaderBaseNS::CEE_LDELEM_U2, ReaderBaseNS::CEE_LDELEM_I4,
ReaderBaseNS::CEE_LDELEM_U4, ReaderBaseNS::CEE_LDELEM_I8,
ReaderBaseNS::CEE_LDELEM_I, ReaderBaseNS::CEE_LDELEM_R4,
ReaderBaseNS::CEE_LDELEM_R8, ReaderBaseNS::CEE_LDELEM_REF,
ReaderBaseNS::CEE_STELEM_I, ReaderBaseNS::CEE_STELEM_I1,
ReaderBaseNS::CEE_STELEM_I2, ReaderBaseNS::CEE_STELEM_I4,
ReaderBaseNS::CEE_STELEM_I8, ReaderBaseNS::CEE_STELEM_R4,
ReaderBaseNS::CEE_STELEM_R8, ReaderBaseNS::CEE_STELEM_REF,
ReaderBaseNS::CEE_LDELEM, ReaderBaseNS::CEE_STELEM,
ReaderBaseNS::CEE_UNBOX_ANY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED5,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED6,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED7,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED9,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED10,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED11,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED12,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED13,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED14,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED15,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED16,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED17,
ReaderBaseNS::CEE_CONV_OVF_I1, ReaderBaseNS::CEE_CONV_OVF_U1,
ReaderBaseNS::CEE_CONV_OVF_I2, ReaderBaseNS::CEE_CONV_OVF_U2,
ReaderBaseNS::CEE_CONV_OVF_I4, ReaderBaseNS::CEE_CONV_OVF_U4,
ReaderBaseNS::CEE_CONV_OVF_I8, ReaderBaseNS::CEE_CONV_OVF_U8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED50,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED18,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED19,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED20,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED21,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED22,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED23,
ReaderBaseNS::CEE_REFANYVAL, ReaderBaseNS::CEE_CKFINITE,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED24,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED25,
ReaderBaseNS::CEE_MKREFANY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED59,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED60,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED61,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED62,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED63,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED64,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED65,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED66,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED67,
ReaderBaseNS::CEE_LDTOKEN, ReaderBaseNS::CEE_CONV_U2,
ReaderBaseNS::CEE_CONV_U1, ReaderBaseNS::CEE_CONV_I,
ReaderBaseNS::CEE_CONV_OVF_I, ReaderBaseNS::CEE_CONV_OVF_U,
ReaderBaseNS::CEE_ADD_OVF, ReaderBaseNS::CEE_ADD_OVF_UN,
ReaderBaseNS::CEE_MUL_OVF, ReaderBaseNS::CEE_MUL_OVF_UN,
ReaderBaseNS::CEE_SUB_OVF, ReaderBaseNS::CEE_SUB_OVF_UN,
ReaderBaseNS::CEE_ENDFINALLY, ReaderBaseNS::CEE_LEAVE,
ReaderBaseNS::CEE_LEAVE_S, ReaderBaseNS::CEE_STIND_I,
ReaderBaseNS::CEE_CONV_U, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL};
// Array which maps prefixed bytecode to WVM opcode.
static const ReaderBaseNS::OPCODE PrefixedByteCodes[33] = {
ReaderBaseNS::CEE_ARGLIST, ReaderBaseNS::CEE_CEQ,
ReaderBaseNS::CEE_CGT, ReaderBaseNS::CEE_CGT_UN,
ReaderBaseNS::CEE_CLT, ReaderBaseNS::CEE_CLT_UN,
ReaderBaseNS::CEE_LDFTN, ReaderBaseNS::CEE_LDVIRTFTN,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED56,
ReaderBaseNS::CEE_LDARG, ReaderBaseNS::CEE_LDARGA,
ReaderBaseNS::CEE_STARG, ReaderBaseNS::CEE_LDLOC,
ReaderBaseNS::CEE_LDLOCA, ReaderBaseNS::CEE_STLOC,
ReaderBaseNS::CEE_LOCALLOC,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED57,
ReaderBaseNS::CEE_ENDFILTER, ReaderBaseNS::CEE_UNALIGNED,
ReaderBaseNS::CEE_VOLATILE, ReaderBaseNS::CEE_TAILCALL,
ReaderBaseNS::CEE_INITOBJ, ReaderBaseNS::CEE_CONSTRAINED,
ReaderBaseNS::CEE_CPBLK, ReaderBaseNS::CEE_INITBLK,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED69,
ReaderBaseNS::CEE_RETHROW,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED51,
ReaderBaseNS::CEE_SIZEOF, ReaderBaseNS::CEE_REFANYTYPE,
ReaderBaseNS::CEE_READONLY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED53,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED54
};

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

@ -207,7 +207,7 @@ class FlowGraphNodeOffsetList;
/// \brief Exception information for the Jit's exception filter
///
/// The jit may need to examine propagating exceptions via a filter to
/// The jit may need to examine propagating exceptions via a filter to
/// determine if the jit needs to take any special actions. This struct
/// provides some extra context for the jit to consider when filtering.
struct RuntimeFilterParams {
@ -231,40 +231,40 @@ struct RuntimeFilterParams {
/// By convention we only create these structures when the value class
/// actually has GC pointers, so \p NumGCPtrs should be nonzero.
struct GCLayout {
uint32_t NumGCPointers; ///< Total number of gc pointers to report
uint8_t GCPointers[0]; ///< Array indicating location of the gc pointers
uint32_t NumGCPointers; ///< Total number of gc pointers to report
uint8_t GCPointers[0]; ///< Array indicating location of the gc pointers
};
/// \brief Structure used to pass argument information from rdrCall to GenCall.
///
/// ReaderBase (which implements \p rdrCall) doesn't know how the derived
/// ReaderBase (which implements \p rdrCall) doesn't know how the derived
/// Reader (which implements \p GenCall) will represent type information, so it
/// uses \p ArgType and \p ArgClass to describe the type of the argument, and
/// \p ArgNode to describe its value.
struct CallArgTriple {
IRNode *ArgNode; ///< Opaque pointer to IR for argument value
CorInfoType ArgType; ///< Low-level type of the argument
CORINFO_CLASS_HANDLE ArgClass; ///< Extra type info for pointers and similar
IRNode *ArgNode; ///< Opaque pointer to IR for argument value
CorInfoType ArgType; ///< Low-level type of the argument
CORINFO_CLASS_HANDLE ArgClass; ///< Extra type info for pointers and similar
};
/// Structure representing a linked list of flow graph nodes
struct FlowGraphNodeList {
FlowGraphNode *Block; ///< Head node in the list
FlowGraphNodeList *Next; ///< Pointer to next list cell
FlowGraphNode *Block; ///< Head node in the list
FlowGraphNodeList *Next; ///< Pointer to next list cell
};
/// Structure representing a linked list of flow graph nodes and
/// for each node, a related node.
struct FlowGraphNodeWorkList {
FlowGraphNode *Block; ///< Head node in the list
FlowGraphNodeWorkList *Next; ///< Pointer to next list cell
FlowGraphNode *Parent; ///< Related node
FlowGraphNode *Block; ///< Head node in the list
FlowGraphNodeWorkList *Next; ///< Pointer to next list cell
FlowGraphNode *Parent; ///< Related node
};
/// \brief Enum describing pointer alignment.
enum ReaderAlignType {
Reader_AlignNatural = (uint8_t)~0, ///< Default natural alignment
Reader_AlignUnknown = 0, ///< Unknown alignment
Reader_AlignUnknown = 0, ///< Unknown alignment
Reader_Align1 = 1, ///< Byte alignment
Reader_Align2 = 2, ///< Word alignment
Reader_Align4 = 4, ///< DWord alignment
@ -276,13 +276,13 @@ enum ReaderAlignType {
/// These are used to describe locals or parameters that have special
/// meaning during code generation.
enum ReaderSpecialSymbolType {
Reader_NotSpecialSymbol = 0, ///< Nothing special
Reader_ThisPtr, ///< Current this pointer for method
Reader_UnmodifiedThisPtr, ///< This pointer param passed to method
Reader_VarArgsToken, ///< Special param for varargs support
Reader_InstParam, ///< Special param for shared generics
Reader_SecurityObject, ///< Local used for security checking
Reader_GenericsContext ///< Local holding shared generics context
Reader_NotSpecialSymbol = 0, ///< Nothing special
Reader_ThisPtr, ///< Current this pointer for method
Reader_UnmodifiedThisPtr, ///< This pointer param passed to method
Reader_VarArgsToken, ///< Special param for varargs support
Reader_InstParam, ///< Special param for shared generics
Reader_SecurityObject, ///< Local used for security checking
Reader_GenericsContext ///< Local holding shared generics context
};
/// \brief Types of pointers
@ -301,14 +301,14 @@ enum ReaderPtrType {
/// When reading MSIL, different kinds of exceptions can be thrown, and this
/// enum decribes the possibilities.
enum ReaderExceptionType {
Reader_LocalVerificationException, ///< Verifier local check failed
Reader_GlobalVerificationException, ///< Verifier global check failed
Reader_LocalVerificationException, ///< Verifier local check failed
Reader_GlobalVerificationException, ///< Verifier global check failed
};
/// Common base class for reader exceptions
class ReaderException {
public:
ReaderExceptionType Type; ///< Type of the exception
ReaderExceptionType Type; ///< Type of the exception
};
// The TryRegion graph allows us to build a region tree that captures the
@ -328,9 +328,9 @@ class ReaderBase; // Forward declaration
/// The MSIL instruction set operates on a stack machine. Instructions
/// with operands may take them from the stack (if not some kind of
/// immediate) and the results of instruction are pushed on the operand stack.
/// The MSIL operands are translated by the reader into IRNodes.
/// The operand stack is represented by a stack of pointers to the
/// IRNodes for the operands.
/// The MSIL operands are translated by the reader into IRNodes.
/// The operand stack is represented by a stack of pointers to the
/// IRNodes for the operands.
///
/// ReaderStack is an abstract class but we do specify that its state is
/// expressed using an std::vector<IRNode*>. So some of the simple
@ -338,15 +338,14 @@ class ReaderBase; // Forward declaration
/// left to be implemented by a derived class.
class ReaderStack {
protected:
std::vector<IRNode*> Stack;
protected:
std::vector<IRNode *> Stack;
public:
/// \brief Mutable iterator to elements of the stack from bottom to top.
///
/// This is the same as the underlying vector iterator.
typedef std::vector<IRNode*>::iterator iterator;
typedef std::vector<IRNode *>::iterator iterator;
/// \brief Pop the top element off the operand stack.
///
@ -364,16 +363,12 @@ public:
/// \brief Make the operand stack empty.
///
/// \post The stack is empty.
void clearStack() {
Stack.clear();
}
void clearStack() { Stack.clear(); }
/// \brief Test whether the stack is empty.
///
/// \return True if the stack is empty
bool empty() {
return Stack.empty();
}
bool empty() { return Stack.empty(); }
/// \brief If the stack is not empty, cause an assertion failure.
virtual void assertEmpty() = 0;
@ -381,19 +376,13 @@ public:
/// \brief get the number of operands on the operand stack.
///
/// \return The number of elements in the stack.
uint32_t size() {
return Stack.size();
}
uint32_t size() { return Stack.size(); }
/// \brief Return begin iterator for iterating from bottom to top of stack.
iterator begin() {
return Stack.begin();
}
iterator begin() { return Stack.begin(); }
/// \brief Return begin iterator for iterating from bottom to top of stack.
iterator end() {
return Stack.end();
}
iterator end() { return Stack.end(); }
#if defined(_DEBUG)
/// \brief Print the contents of the operand stack onto the debug output.
@ -632,77 +621,195 @@ fgEdgeListGetNextPredecessorActual(FlowGraphEdgeList *FgEdge);
FlowGraphEdgeList *fgNodeGetSuccessorListActual(FlowGraphNode *Fg);
FlowGraphEdgeList *fgNodeGetPredecessorListActual(FlowGraphNode *Fg);
// Interface to GenIR defined IRNode structure
// Implementation Supplied by Jit Client
/// \name Client IR interface
///
///@{
/// \brief Iterate forward through the client IR
///
/// Within a basic block, the client IR nodes will form a linear sequence.
/// This method advances from one node to the next in that sequence.
///
/// \param Node The current IR node
/// \returns The next IR node
IRNode *irNodeGetNext(IRNode *Node);
bool irNodeIsBranch(IRNode *Node);
/// \brief Searching forward, find the first IR node with an MSIL offset
/// greater or equal to the indicated offset.
///
/// Ask the client to scan forward through the IR starting \p Node, searching
/// for a Node whose MSIL offset is greater than or equal to the provided
/// \p Offset.
///
/// \param Node The starting node for the search
/// \param Offset The MSIL offset
/// \returns The first IR node that is at/after the indicated offset
IRNode *irNodeGetInsertPointAfterMSILOffset(IRNode *Node, uint32_t Offset);
/// \brief Searching backwards, find the first IR node with an MSIL offset less
/// than the indicated offset.
///
/// Ask the client to scan backwards through the IR starting \p Node, searching
/// for a Node whose MSIL offset is less than the provided \p Offset.
///
/// \param Node The starting node for the search
/// \param Offset The MSIL offset
/// \returns The first IR node that is before the indicated offset
IRNode *irNodeGetInsertPointBeforeMSILOffset(IRNode *Node, uint32_t Offset);
/// Get the first IR node in the indicated IR node's block
///
/// \param HandlerStartNode The indicated IR node
/// \returns The first IR node in the same block
IRNode *
irNodeGetFirstLabelOrInstrNodeInEnclosingBlock(IRNode *HandlerStartNode);
/// Get the MSIL offset for the indicated IR node
///
/// \param Node The indicated IR node
/// \returns MSIL offset for this IR node
uint32_t irNodeGetMSILOffset(IRNode *Node);
/// Set the MSIL offset for this IR node
///
/// \param Node The node in question
/// \param Offset The MSIL offset to use
void irNodeLabelSetMSILOffset(IRNode *Node, uint32_t Offset);
/// Set the MSIL offset for this branch IR node
///
/// \param BranchNode The node in question
/// \param Offset The MSIL offset to use
void irNodeBranchSetMSILOffset(IRNode *BranchNode, uint32_t Offset);
/// Set the MSIL offset for this exception branch IR node.
///
/// \param BranchNode The node in question
/// \param Offset The MSIL offset to use
void irNodeExceptSetMSILOffset(IRNode *BranchNode, uint32_t Offset);
void irNodeInsertBefore(IRNode *InsertionPointTuple, IRNode *NewNode);
void irNodeInsertAfter(IRNode *InsertionPointTuple, IRNode *NewNode);
/// Insert an IR node before another IR node
///
/// \param InsertionPoint Existing IR to use as insertion point
/// \param NewNode New IR to insert before \p InsertionPoint
void irNodeInsertBefore(IRNode *InsertionPoint, IRNode *NewNode);
/// Insert an IR node after another IR node
///
/// \param InsertionPoint Existing IR to use as insertion point
/// \param NewNode New IR to insert after \p InsertionPoint
void irNodeInsertAfter(IRNode *InsertionPoint, IRNode *NewNode);
/// Set the EH region for an IR node
///
/// \param Node The IR node of interest
/// \param Region The EH region to associate with the \p Node
void irNodeSetRegion(IRNode *Node, EHRegion *Region);
/// Get the EH region for an IR node
///
/// \param Node The IR node of interest
/// \returns The EH region associated with \p Node
EHRegion *irNodeGetRegion(IRNode *Node);
/// Get the flow graph node for an IR node
///
/// \param Node The IR node of interest
/// \returns The flow graph node containing \p Node
FlowGraphNode *irNodeGetEnclosingBlock(IRNode *Node);
/// Determine if an IR node is a label
///
/// \param Node The IR node of interest
/// \returns True iff \p Node is a label
bool irNodeIsLabel(IRNode *Node);
/// Determine if this IR node is a branch
///
/// \param Node The IR node to examine
/// \returns True iff \p Node is a branch
bool irNodeIsBranch(IRNode *Node);
/// Determine if an IR node is an EH flow annotation
///
/// \param Node The IR node of interest
/// \returns True iff \p Node is an EH flow annotation
bool irNodeIsEHFlowAnnotation(IRNode *Node);
/// Determine if an IR node is an EH handler flow annotation
///
/// \param Node The IR node of interest
/// \returns True iff \p Node is an EH handler flow annotation
bool irNodeIsHandlerFlowAnnotation(IRNode *Node);
// Interface to GenIR defined BranchList structure
// Implementation Supplied by Jit Client.
///@}
/// \name Client BranchList interface
/// Used by \p fgFixRecursiveEdges to undo branches added by the optimistic
/// recursive tail call transformation. Implementation supplied by the client.
///@{
/// Get the next branch list item
///
/// \param BranchList Current list item
/// \returns Next list item
BranchList *branchListGetNext(BranchList *BranchList);
/// Get the client IR for a branch list item
///
/// \param BranchList Current list item
/// \returns Client IR for the item
IRNode *branchListGetIRNode(BranchList *BranchList);
struct VerificationBranchInfo {
uint32_t SrcOffset;
uint32_t TargetOffset;
IRNode *BranchOp;
bool IsLeave;
///@}
VerificationBranchInfo *Next;
/// Record information about a branch for verification
struct VerificationBranchInfo {
uint32_t SrcOffset; ///< MSIL offset of the branch
uint32_t TargetOffset; ///< MSIL offset of the branch target
IRNode *BranchOp; ///< Client IR for the branch
bool IsLeave; ///< True if branch is from a leave opcode
VerificationBranchInfo *Next; ///< Next branch to verify
};
/// Translate a call opcode from the general MSIL opcode enumeration into
/// the call-specific opcode enumeration.
/// \param Opcode MSIL opcode
/// \returns MSIL call opcode
ReaderBaseNS::CallOpcode remapCallOpcode(ReaderBaseNS::OPCODE Opcode);
/// \brief Parameters needed for converting MSIL to client IR for
/// a particular flow graph node.
///
/// The MSIL conversion for a flow graph node happens within a protected region
/// set up by \p readBytesForFlowGraphNode. This struct is used to pass state
/// The MSIL conversion for a flow graph node happens within a protected region
/// set up by \p readBytesForFlowGraphNode. This struct is used to pass state
/// information back and forth to the helper method.
struct ReadBytesForFlowGraphNodeHelperParam {
ReaderBase *This; ///< The base reader instance
ReaderException *Excep; ///< Captured exception state
FlowGraphNode *Fg; ///< The flow graph node being processed
bool IsVerifyOnly; ///< True if the reader is just verifying
uint32_t CurrentOffset; ///< Offset within the IL stream
bool LocalFault; ///< True if the current node failed
///< verification
bool HasFallThrough; ///< True if the control flows off the end
///< of this node into the next one
VerificationState *VState; ///< Verifier state for the node
bool VerifiedEndBlock; ///< True if we've verified the block has
///< an appropriate ending
ReaderBase *This; ///< The base reader instance
ReaderException *Excep; ///< Captured exception state
FlowGraphNode *Fg; ///< The flow graph node being processed
bool IsVerifyOnly; ///< True if the reader is just verifying
uint32_t CurrentOffset; ///< Offset within the IL stream
bool LocalFault; ///< True if the current node failed
///< verification
bool HasFallThrough; ///< True if the control flows off the end
///< of this node into the next one
VerificationState *VState; ///< Verifier state for the node
bool VerifiedEndBlock; ///< True if we've verified the block has
///< an appropriate ending
};
static const int32_t SizeOfCEECall = 5;
static const int32_t SizeOfCEECall = 5; ///< size of MSIL call plus operand
/// \brief \p ReaderBase is an abstract base class for tools that need to
/// \brief \p ReaderBase is an abstract base class for tools that need to
/// both model MSIL and interact with the CoreCLR ExecutionEngine or some
/// similar repository of knowledge.
///
/// \p ReaderBase is intended to be used as a traversal agent through
/// MSIL for a derived \p Reader class (aka *Client*) with more specialized
/// requirements.
///
/// For instance an MSIL Verifier or a JIT might derive from \p ReaderBase
/// MSIL for a derived \p Reader class (aka *Client*) with more specialized
/// requirements.
///
/// For instance an MSIL Verifier or a JIT might derive from \p ReaderBase
/// and provide suitable implementations of the companion classes.
class ReaderBase {
friend class ReaderCallTargetData;
@ -727,9 +834,18 @@ public:
FlowGraphNode *CurrentFgNode;
/// True if this method contains the 'localloc' MSIL opcode.
bool HasLocAlloc;
uint32_t CurrInstrOffset; // current instruction IL offset
uint32_t NextInstrOffset; // next instruction IL offset
/// True if the client has optimistically transformed tail.
/// recursion into a branch.
bool HasOptimisticTailRecursionTransform;
/// The current instruction's IL offset.
uint32_t CurrInstrOffset;
/// The next instruction's IL offset.
uint32_t NextInstrOffset;
private:
// Private data (not available to derived client class)
@ -809,7 +925,7 @@ private:
public:
bool AreInlining;
/// \brief Constructor
///
/// Initializes the base part of the reader object, setting all fields to
@ -824,7 +940,7 @@ public:
/// \brief Main entry point for the reader
///
/// This method orchestrates client processing of the MSIL for the method
/// This method orchestrates client processing of the MSIL for the method
/// specified by the constructor parameters. The processing runs in a series
/// of steps:
/// 1. Pre pass to allow the client to do initialization
@ -835,14 +951,14 @@ public:
//// control flow inducing instructions in the MSIL.
/// 4. Middle pass to allow the client to process the flow graph
/// 5. Depth-first preorder traversal of the blocks in the flow graph. Client
/// is invoked on each instruction in the block.
/// is invoked on each instruction in the block.
/// 6. Flow graph cleanup
/// 7. Final pass to allow the client a chance to finish up
void msilToIR();
/// \brief Set up parameters and locals (autos)
///
/// Uses the method and local signatures and information from the EE to
/// Uses the method and local signatures and information from the EE to
/// direct client processing for the method parameters and the local
/// variables of the method.
///
@ -853,11 +969,11 @@ public:
/// \brief Set up parameters
///
/// Uses the method signature and information from the EE to direct the
/// Uses the method signature and information from the EE to direct the
/// client to set up processing for method parameters.
///
/// \params NumParams Number of parameters to the method. Note this may
/// include implicit parameters like the this pointer.
/// include implicit parameters like the this pointer.
void buildUpParams(uint32_t NumParams);
/// \brief Set up locals (autos)
@ -871,7 +987,7 @@ public:
/// \brief Process the next element (argument or local) in a signature
///
/// Utility routine used by \p buildUpParams and \p buildUpLocals to iterate
/// through a signature and obtain more detailed information about each
/// through a signature and obtain more detailed information about each
/// element.
///
/// \params ArgListHandle Handle for the current element of the signature
@ -915,7 +1031,7 @@ public:
#if defined(_DEBUG)
/// \brief Debug-only reader function to print range of MSIL.
///
/// Print the MSIL in the buffer for the given range. Output emitted via
/// Print the MSIL in the buffer for the given range. Output emitted via
/// \p dbPrint().
///
/// \param Buf Buffer containing MSIL bytecode
@ -927,7 +1043,7 @@ public:
/// \brief Determine the effect of this instruction on the operand stack
///
/// Many MSIL instructions push or pop operands from the stack, or both pop
/// and push operands. This method determines the net number of pushes and
/// and push operands. This method determines the net number of pushes and
/// pops for a particular instruction.
///
/// \param Opcode The MSIL opcode for the instruction
@ -941,8 +1057,8 @@ public:
private:
/// \brief Determine if a call instruction is a candidate to be a tail call
///
/// The client may decide to give special tail-call treatment to calls that
/// are followed closely by returns, even if the calls are not marked with
/// The client may decide to give special tail-call treatment to calls that
/// are followed closely by returns, even if the calls are not marked with
/// the tail prefix. This method determines if such treatment is possible.
///
/// \param ILInput Pointer to the start of the MSIL bytecode stream
@ -950,7 +1066,7 @@ private:
/// \param NextOffset Offset into the stream just past the call
/// \param Token Token value for calls that have sig tokens
///
/// \returns True if treating this call as a tail call is
/// \returns True if treating this call as a tail call is
/// reasonble.
bool isUnmarkedTailCall(uint8_t *ILInput, uint32_t ILInputSize,
uint32_t NextOffset, mdToken Token);
@ -962,18 +1078,18 @@ private:
/// \param NextOffset Offset into the stream just past the call
/// \param Token Token value for calls that have sig tokens
///
/// \returns True if treating this call as a tail call is
/// \returns True if treating this call as a tail call is
/// reasonble.
bool isUnmarkedTailCallHelper(uint8_t *ILInput, uint32_t ILInputSize,
uint32_t NextOffset, mdToken Token);
/// \brief Check if the current instruction is a valid explicit tail call
///
/// Verify that this call is a valid explicit tail call. The call must be
/// closely followed by a return.
///
/// \param ILOffset Offset of the call instruction in the IL stream
/// \param AllowPop true if it is acceptable for the call to be
/// \param AllowPop true if it is acceptable for the call to be
/// followed by a single pop before reaching the
/// return.
/// \returns True if the current instruction is a valid explicit
@ -983,7 +1099,7 @@ private:
/// \brief Convert the MSIL for this flow graph node into the client IR
///
/// Orchestrates client processing the MSIL in this flow graph node,
/// filling in the block contents. This outer method sets up a parameter
/// filling in the block contents. This outer method sets up a parameter
/// block for its helper method and the invokes its helper within a protected
/// region so that various errors can be caught and handled appropriately.
///
@ -993,7 +1109,7 @@ private:
/// \brief Helper method for \p readBytesForFlowGraphNode
///
/// Helper method that orchestrates client processing the MSIL in a flow
/// Helper method that orchestrates client processing the MSIL in a flow
/// graph node specified by the parameters.
///
/// \param Param Encapsulated state from the main method
@ -1002,7 +1118,6 @@ private:
readBytesForFlowGraphNodeHelper(ReadBytesForFlowGraphNodeHelperParam *Param);
private:
/// \brief Perform special processing for blocks that start EH regions.
///
/// Uses the \p CurrentFgNode to determine which block to process. Ensures
@ -1047,9 +1162,9 @@ private:
///
/// This pass determines the legal starting points of all MSIL instructions,
/// locates all block-ending instructions (branches and similar) and all
/// branch targets, and builds blocks that end with the block-ending
/// branch targets, and builds blocks that end with the block-ending
/// instructions and have appropriate flow graph edges to successor blocks.
///
///
/// \param Fg Nominal entry node for the method
/// \param Buffer Buffer of MSIL bytecodes
/// \param BufferSize Length of the buffer in bytes
@ -1082,7 +1197,7 @@ private:
///
/// This method scans all the successor blocks of \p CurrBlock, and
/// if there are any, creates new work list nodes for these successors,
/// marks them as visited, and (despite the method name) prepends them,
/// marks them as visited, and (despite the method name) prepends them,
/// returning a new worklist head node.
///
/// \param Worklist The current worklist of unvisited blocks
@ -1124,7 +1239,7 @@ private:
///
/// When the flow graph is initially built, branches target temporary
/// graph nodes. This function updates all of the branches that target
/// a particular temporary node with the actual node representing the
/// a particular temporary node with the actual node representing the
/// target in the flow graph.
///
/// \param Offset The MSIL offset of the branch target
@ -1137,7 +1252,7 @@ private:
/// \brief Update all branches with temporary targets
///
/// Walks the list of branch target offsets, invoking
/// Walks the list of branch target offsets, invoking
/// \p fgReplaceBranchTarget to update all branches with that target to
/// refer to the proper blocks.
void fgReplaceBranchTargets();
@ -1182,7 +1297,7 @@ private:
/// \brief Create IR for an endfinally instruction
///
/// Have the client create IR for an endfinally instruction. Note
/// there can be more than one of these in a finally region.
/// there can be more than one of these in a finally region.
///
/// \param BlockNode the block that is the end of the finally
/// \param CurentOffset msil offset for the endfinally instruction
@ -1215,9 +1330,9 @@ private:
/// This method sees if there is an existing flow graph node that begins at
/// the indicated target. If so, \p Node is set to this block. If not, a
/// temporary block is allocated to use as a target, and an entry is added
/// to the \p NodeOffsetListArray so a subsequent pass can update the
/// to the \p NodeOffsetListArray so a subsequent pass can update the
/// temporary target blocks to real target blocks.
///
///
/// \param Node [out] Node to use as the branch target
/// \param TargetOffset MSIL offset of the branch target
/// \returns List node of target in offset list
@ -1229,7 +1344,7 @@ private:
/// \param Fg flow graph node containing the leave
/// \param LeaveOffset MSIL offset of the leave
/// \param LeaveTarget MSIL offset of the leave's target
/// \param EndsWithNonLocalGoto [out] Target of the leave is not the
/// \param EndsWithNonLocalGoto [out] Target of the leave is not the
/// canonical exit offset of the region
///
/// \returns True if this is a nonlocal leave
@ -1259,7 +1374,6 @@ private:
CORINFO_CLASS_HANDLE Class);
void domInfoRecordClassInit(FlowGraphNode *Fg, CORINFO_CLASS_HANDLE Class);
// =============================================================================
// =============================================================================
// ======= EIT Verification ===============================================
@ -2014,10 +2128,10 @@ public:
virtual IRNode *loadConstantR4(float Value) = 0;
virtual IRNode *loadConstantR8(double Value) = 0;
virtual IRNode *loadElem(ReaderBaseNS::LdElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2) = 0;
virtual IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, bool IsReadOnly) = 0;
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
IRNode *Array) = 0;
virtual IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken,
IRNode *Index, IRNode *Array, bool IsReadOnly) = 0;
virtual IRNode *loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
ReaderAlignType Alignment, bool IsVolatile) = 0;
virtual IRNode *loadIndir(ReaderBaseNS::LdIndirOpcode Opcode, IRNode *Address,
@ -2106,9 +2220,11 @@ public:
virtual void storeArg(uint32_t LocOrdinal, IRNode *Arg1,
ReaderAlignType Alignment, bool IsVolatile) = 0;
virtual void storeElem(ReaderBaseNS::StElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, IRNode *Arg3) = 0;
virtual void storeElemRefAny(IRNode *Value, IRNode *Index, IRNode *Obj);
CORINFO_RESOLVED_TOKEN *ResolvedToken,
IRNode *ValueToStore, IRNode *Index,
IRNode *Array) = 0;
virtual void storeElemRefAny(IRNode *ValueToStore, IRNode *Index,
IRNode *Array);
virtual void storeField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, ReaderAlignType Alignment,
bool IsVolatile) = 0;

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

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

@ -9,8 +9,8 @@
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Declares the GenIR class, which overrides ReaderBase to generate LLVM IR
/// from MSIL bytecode.
/// \brief Declares the GenIR class, which overrides ReaderBase to generate LLVM
/// IR from MSIL bytecode.
///
//===----------------------------------------------------------------------===//
@ -39,7 +39,8 @@ public:
/// in this basic block.
uint32_t StartMSILOffset;
/// Byte offset that is just past the last MSIL instruction of the Basic Block.
/// Byte offset that is just past the last MSIL instruction of the Basic
/// Block.
uint32_t EndMSILOffset;
/// In algorithms traversing the flow graph, used to track which basic blocks
@ -54,8 +55,8 @@ public:
///
/// The MSIL reader expects to use a type called IRNode to represent the
/// translation of the MSIL instructions. But the LLVM infrastructure uses
/// the llvm::Value type as the base class of its IR representation.
/// To reconcile these we make IRNode a class that merely derives from
/// the llvm::Value type as the base class of its IR representation.
/// To reconcile these we make IRNode a class that merely derives from
/// llvm::Value.
class IRNode : public llvm::Value {};
@ -78,15 +79,14 @@ public:
virtual FlowGraphNode *getSource() = 0;
};
/// \brief A list of predecessor edges of a given flow graph node.
///
/// This is used for iterating over the predecessors of a flow graph node.
/// After creating the predecessor edge list the getSource method is used
/// to get the first predecessor (if any). As long as the result of getSource()
/// is non-null, the moveNext() method may be used to advance to the next
/// predecessor edge. When getSource() returns null there are no more
/// predecessor edges (or predecessors).
/// predecessor edge. When getSource() returns null there are no more
/// predecessor edges (or predecessors).
/// \invariant The current edge iterator either points to a real edge or else
/// equals the end iterator meaning the list has been exhausted.
class FlowGraphPredecessorEdgeList : public FlowGraphEdgeList {
@ -103,7 +103,7 @@ public:
/// Move the current location in the flow graph edge list to the next edge.
/// \pre The current edge has not reached the end of the edge list.
/// \post The current edge has been advanced to the next, or has possibly
/// reached the end iterator (meaning no more predecessors).
/// reached the end iterator (meaning no more predecessors).
void moveNext() override { PredIterator++; }
/// \return The sink of the current edge which will be \p Fg node.
@ -112,9 +112,9 @@ public:
return (FlowGraphNode *)PredIterator.getUse().get();
}
/// \return The source of the current edge which will be one of the predecessors
/// of the \p Fg node, unless the list has been exhausted in which case
/// return nullptr.
/// \return The source of the current edge which will be one of the
/// predecessors of the \p Fg node, unless the list has been exhausted in
/// which case return nullptr.
FlowGraphNode *getSource() override {
return (PredIterator == PredIteratorEnd) ? nullptr
: (FlowGraphNode *)*PredIterator;
@ -131,8 +131,8 @@ private:
/// After creating the successor edge list the getSink method is used
/// to get the first successor (if any). As long as the result of getSink()
/// is non-null, the moveNext() method may be used to advance to the next
/// successor edge. When getSink() returns null there are no more
/// successor edges (or successors).
/// successor edge. When getSink() returns null there are no more
/// successor edges (or successors).
/// \invariant The current edge iterator either points to a real edge or else
/// equals the end iterator meaning the list has been exhausted.
class FlowGraphSuccessorEdgeList : public FlowGraphEdgeList {
@ -150,7 +150,7 @@ public:
/// Move the current location in the flow graph edge list to the next edge.
/// \pre The current edge has not reached the end of the edge list.
/// \post The current edge has been advanced to the next, or has possibly
/// reached the end iterator (meaning no more successors).
/// reached the end iterator (meaning no more successors).
void moveNext() override { SuccIterator++; }
/// \return The sink of the current edge which will be one of the successors
@ -177,25 +177,26 @@ private:
/// The MSIL instruction set operates on a stack machine. Instructions
/// with operands may take them from the stack (if not some kind of
/// immediate) and the results of instruction are pushed on the operand stack.
/// The MSIL operands are translated by the reader into IRNodes.
/// The operand stack is represented by a stack of pointers to the
/// IRNodes for the operands.
/// The MSIL operands are translated by the reader into IRNodes.
/// The operand stack is represented by a stack of pointers to the
/// IRNodes for the operands.
///
/// This class completes the implementation of the ReaderStack base class.
class GenStack : public ReaderStack {
private:
/// Owner of the operand stack.
ReaderBase *Reader;
public:
/// \brief Construct a GenStack with an initial capacity of \a MaxStack.
///
/// \param MaxStack Suggested capacity for the stack. However the stack
/// is allowed to grow larger than MaxStack as needed (possibly due to
/// function inlining).
/// function inlining).
/// \param Reader The ReaderBase that owns this operand stack. This is needed
/// so that storage can be allocated from the lifetime of the reader.
GenStack(uint32_t MaxStack, ReaderBase *Reader);
/// \brief Pop the top element off the operand stack.
///
/// \return The top element of the stack.
@ -250,9 +251,7 @@ public:
// MSIL Routines - client defined routines that are invoked by the reader.
// One will be called for each msil opcode.
uint32_t getPointerByteSize() override {
return TargetPointerSizeInBits / 8;
}
uint32_t getPointerByteSize() override { return TargetPointerSizeInBits / 8; }
void opcodeDebugPrint(uint8_t *Buf, unsigned StartOffset,
unsigned EndOffset) override {
@ -305,11 +304,9 @@ public:
FlowGraphNode *fgNodeGetNext(FlowGraphNode *FgNode) override;
uint32_t fgNodeGetStartMSILOffset(FlowGraphNode *Fg) override;
void fgNodeSetStartMSILOffset(FlowGraphNode *Fg,
uint32_t Offset) override;
void fgNodeSetStartMSILOffset(FlowGraphNode *Fg, uint32_t Offset) override;
uint32_t fgNodeGetEndMSILOffset(FlowGraphNode *Fg) override;
void fgNodeSetEndMSILOffset(FlowGraphNode *FgNode,
uint32_t Offset) override;
void fgNodeSetEndMSILOffset(FlowGraphNode *FgNode, uint32_t Offset) override;
bool fgNodeIsVisited(FlowGraphNode *FgNode) override;
void fgNodeSetVisited(FlowGraphNode *FgNode, bool Visited) override;
@ -335,14 +332,10 @@ public:
IRNode *loadConstantR4(float Value) override;
IRNode *loadConstantR8(double Value) override;
IRNode *loadElem(ReaderBaseNS::LdElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2) override {
throw NotYetImplementedException("loadElem");
};
IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, bool IsReadOnly) override {
throw NotYetImplementedException("loadElemA");
};
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
IRNode *Array) override;
IRNode *loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
IRNode *Array, bool IsReadOnly) override;
IRNode *loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
ReaderAlignType Alignment, bool IsVolatile) override;
@ -425,10 +418,8 @@ public:
void storeArg(uint32_t ArgOrdinal, IRNode *Arg1, ReaderAlignType Alignment,
bool IsVolatile) override;
void storeElem(ReaderBaseNS::StElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, IRNode *Arg3) override {
throw NotYetImplementedException("storeElem");
};
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ValueToStore,
IRNode *Index, IRNode *Array) override;
void storeField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1,
IRNode *Arg2, ReaderAlignType Alignment,
@ -828,15 +819,15 @@ private:
llvm::FunctionType *getFunctionType(CORINFO_SIG_INFO &Sig,
CORINFO_CLASS_HANDLE ThisClass);
llvm::Type *getClassType(CORINFO_CLASS_HANDLE ClassHandle,
bool IsRefClass, bool GetRefClassFields);
llvm::Type *getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
bool GetRefClassFields);
/// Convert node to the desired type.
/// May reinterpret, truncate, or extend as needed.
/// \p Type - Desired type
/// \p Node - Value to be converted
/// \p IsSigned - Perform sign extension if necessary, otherwise
/// integral values are zero extended
/// \param Type Desired type
/// \param Node Value to be converted
/// \param IsSigned Perform sign extension if necessary, otherwise
/// integral values are zero extended
IRNode *convert(llvm::Type *Type, llvm::Value *Node, bool IsSigned);
llvm::Type *binaryOpType(llvm::Type *Type1, llvm::Type *Type2);
@ -853,10 +844,77 @@ private:
IRNode *getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
ReaderAlignType Alignment, uint32_t *Align);
/// Generate instructions for loading value of the specified type at the
/// specified address.
///
/// \param Address Address to load from.
/// \param Ty llvm type of the value to load.
/// \param CorType CorInfoType of the value to load.
/// \param ResolvedToken Resolved token corresponding to the type of the value
/// to load.
/// \param AlignmentPrefix Alignment of the value.
/// \param IsVolatile true iff the load is volatile.
/// \param AddressMayBeNull true iff the address may be null.
/// \returns Value at the specified address.
IRNode *loadAtAddress(IRNode *Address, llvm::Type *Ty, CorInfoType CorType,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType AlignmentPrefix, bool IsVolatile,
bool AddressMayBeNull = true);
IRNode *loadAtAddressNonNull(IRNode *Address, llvm::Type *Ty,
CorInfoType CorType,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType AlignmentPrefix,
bool IsVolatile) {
return loadAtAddress(Address, Ty, CorType, ResolvedToken, AlignmentPrefix,
IsVolatile, false);
}
/// Generate instructions for storing value of the specified type at the
/// specified address.
///
/// \param Address Address to store to.
/// \param ValueToStore Value to store.
/// \param Ty llvm type of the value to store.
/// \param ResolvedToken Resolved token corresponding to the type of the value
/// to store.
/// \param AlignmentPrefix Alignment of the value.
/// \param IsVolatile true iff the store is volatile.
/// \param IsField true iff this is a field address.
/// \param AddressMayBeNull true iff the address may be null.
void storeAtAddress(IRNode *Address, IRNode *ValueToStore, llvm::Type *Ty,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType AlignmentPrefix, bool IsVolatile,
bool IsField, bool AddressMayBeNull);
void storeAtAddressNonNull(IRNode *Address, IRNode *ValueToStore,
llvm::Type *Ty,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType AlignmentPrefix, bool IsVolatile,
bool IsField) {
return storeAtAddress(Address, ValueToStore, Ty, ResolvedToken,
AlignmentPrefix, IsVolatile, IsField, false);
}
void classifyCmpType(llvm::Type *Ty, uint32_t &Size, bool &IsPointer,
bool &IsFloat);
/// Generate a call to the throw helper if the condition is met.
///
/// \param Condition Condition that will trigger the throw.
/// \param HelperId Id of the throw-helper.
/// \param ThrowBlockName Name of the basic block that will contain the throw.
void genConditionalThrow(llvm::Value *Condition, CorInfoHelpFunc HelperId,
const llvm::Twine &ThrowBlockName);
/// Generate array bounds check.
///
/// \param Array Array to be accessed.
/// \param Index Index to be accessed.
/// \returns The input array.
IRNode *genBoundsCheck(IRNode *Array, IRNode *Index);
uint32_t size(CorInfoType CorType);
uint32_t stackSize(CorInfoType CorType);
static bool isSigned(CorInfoType CorType);
@ -864,17 +922,17 @@ private:
/// Convert a result to a valid stack type,
/// generally by either reinterpretation or extension.
/// \p Node - Value to be converted
/// \p CorType - additional information needed to determine if
/// Node's type is signed or unsigned
/// \param Node Value to be converted
/// \param CorType additional information needed to determine if
/// Node's type is signed or unsigned
IRNode *convertToStackType(IRNode *Node, CorInfoType CorType);
/// Convert a result from a stack type to the desired type,
/// generally by either reinterpretation or truncation.
/// \p Node - Value to be converted
/// \p CorType - additional information needed to determine if
/// ResultTy is signed or unsigned
/// \p ResultTy - Desired type
/// \param Node Value to be converted
/// \param CorType additional information needed to determine if
/// ResultTy is signed or unsigned
/// \param ResultTy - Desired type
IRNode *convertFromStackType(IRNode *Node, CorInfoType CorType,
llvm::Type *ResultTy);
@ -883,7 +941,7 @@ private:
/// Create a new temporary variable that can be
/// used anywhere within the method.
///
/// \p Ty - Type for the new variable.
/// \param Ty Type for the new variable.
/// \returns Instruction establishing the variable's location.
llvm::Instruction *createTemporary(llvm::Type *Ty);
@ -913,6 +971,35 @@ private:
return makeLoad(Address, IsVolatile, false);
}
/// Get address of the array element.
///
/// \param Array Array that the element belongs to.
/// \param Index Index of the element.
/// \param ElementTy Type of the element.
/// \returns Value representing the address of the element.
llvm::Value *genArrayElemAddress(IRNode *Array, IRNode *Index,
llvm::Type *ElementTy);
/// Convert ReaderAlignType to byte alighnment to byte alignment.
///
/// \param ReaderAlignment Reader alignment.
/// \returns Alignment in bytes.
uint32_t convertReaderAlignment(ReaderAlignType ReaderAlignment);
/// Get array element type.
///
/// \param Array Array node.
/// \param ResolvedToken Resolved token from ldelem or stelem instruction.
/// \param CorInfoType [IN/OUT] Type of the element (will be resolved for
/// CORINFO_TYPE_UNDEF).
/// \param Alignment - [IN/OUT] Alignment that will be updated for value
/// classes.
/// \returns Array element type.
llvm::Type *getArrayElementType(IRNode *Array,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
CorInfoType *CorType,
ReaderAlignType *Alignment);
private:
LLILCJitContext *JitContext;
llvm::Function *Function;

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

@ -254,9 +254,11 @@ public:
uint32_t UninitObj : 1; // used
uint32_t ByRef : 1; // used
uint32_t ByRefReadOnly : 1;
uint32_t : 3; // unused?
// clang-format off
uint32_t: 3; // unused?
uint32_t ThisPtr : 1; // used
uint32_t : 1; // unused?
uint32_t: 1; // unused?
// clang-format on
uint32_t GenericTypeVar : 1; // used
} Bits;

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

@ -77,9 +77,7 @@ void irNodeLabelSetMSILOffset(IRNode *Node, uint32_t LabelMSILOffset) {
}
// TODO: figure out how we're going to communicate this information.
void irNodeBranchSetMSILOffset(IRNode *BranchNode, uint32_t Offset) {
return;
}
void irNodeBranchSetMSILOffset(IRNode *BranchNode, uint32_t Offset) { return; }
void irNodeExceptSetMSILOffset(IRNode *BranchNode, uint32_t Offset) {
throw NotYetImplementedException("irNodeExceptSetMSILOffset");

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

@ -9,7 +9,8 @@
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Common code for converting MSIL bytecode into some other representation.
/// \brief Common code for converting MSIL bytecode into some other
/// representation.
///
/// The common reader's operation revolves around two central classes.
/// ReaderBase:: the common reader class
@ -94,10 +95,10 @@ ReaderBaseNS::CallOpcode remapCallOpcode(ReaderBaseNS::OPCODE Op) {
/// \param[out] Value When this function returns, the decoded value.
///
/// \returns The number of bytes read from the buffer.
template<typename Type>
template <typename Type>
size_t readValue(const uint8_t *ILCursor, Type *Value) {
// MSIL contains little-endian values; swap the bytes around when compiled
// for big-endian platforms.
// MSIL contains little-endian values; swap the bytes around when compiled
// for big-endian platforms.
#if defined(BIGENDIAN)
for (uint32_t I = 0; I < sizeof(Type); ++I)
((uint8_t *)Value)[I] = ILCursor[sizeof(Type) - I - 1];
@ -112,8 +113,7 @@ size_t readValue(const uint8_t *ILCursor, Type *Value) {
/// \param[in] ILCursor The buffer to read from.
///
/// \returns The decoded value.
template<typename Type>
Type readValue(const uint8_t *ILCursor) {
template <typename Type> Type readValue(const uint8_t *ILCursor) {
Type Value;
readValue(ILCursor, &Value);
return Value;
@ -319,187 +319,15 @@ uint32_t getMSILInstrLength(ReaderBaseNS::OPCODE Opcode, uint8_t *Operand) {
/// \param[out] Operand When this method returns, the address of the
/// returned opcode's operand.
/// \param ReportError Indicates whether or not to report parse errors.
///
///
/// \returns The offset into the input buffer of the next MSIL opcode.
uint32_t parseILOpcode(uint8_t *ILInput, uint32_t ILOffset, uint32_t ILSize,
ReaderBase *Reader, ReaderBaseNS::OPCODE *Opcode,
uint8_t **Operand, bool ReportErrors = true) {
// Illegal opcodes are currently marked as CEE_ILLEGAL. These should
// cause verification errors.
// Illegal opcodes are currently marked as CEE_ILLEGAL. These should
// cause verification errors.
// Array which maps bytecode to WVM opcode.
static const ReaderBaseNS::OPCODE ByteCodes[256] = {
ReaderBaseNS::CEE_NOP, ReaderBaseNS::CEE_BREAK,
ReaderBaseNS::CEE_LDARG_0, ReaderBaseNS::CEE_LDARG_1,
ReaderBaseNS::CEE_LDARG_2, ReaderBaseNS::CEE_LDARG_3,
ReaderBaseNS::CEE_LDLOC_0, ReaderBaseNS::CEE_LDLOC_1,
ReaderBaseNS::CEE_LDLOC_2, ReaderBaseNS::CEE_LDLOC_3,
ReaderBaseNS::CEE_STLOC_0, ReaderBaseNS::CEE_STLOC_1,
ReaderBaseNS::CEE_STLOC_2, ReaderBaseNS::CEE_STLOC_3,
ReaderBaseNS::CEE_LDARG_S, ReaderBaseNS::CEE_LDARGA_S,
ReaderBaseNS::CEE_STARG_S, ReaderBaseNS::CEE_LDLOC_S,
ReaderBaseNS::CEE_LDLOCA_S, ReaderBaseNS::CEE_STLOC_S,
ReaderBaseNS::CEE_LDNULL, ReaderBaseNS::CEE_LDC_I4_M1,
ReaderBaseNS::CEE_LDC_I4_0, ReaderBaseNS::CEE_LDC_I4_1,
ReaderBaseNS::CEE_LDC_I4_2, ReaderBaseNS::CEE_LDC_I4_3,
ReaderBaseNS::CEE_LDC_I4_4, ReaderBaseNS::CEE_LDC_I4_5,
ReaderBaseNS::CEE_LDC_I4_6, ReaderBaseNS::CEE_LDC_I4_7,
ReaderBaseNS::CEE_LDC_I4_8, ReaderBaseNS::CEE_LDC_I4_S,
ReaderBaseNS::CEE_LDC_I4, ReaderBaseNS::CEE_LDC_I8,
ReaderBaseNS::CEE_LDC_R4, ReaderBaseNS::CEE_LDC_R8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED49,
ReaderBaseNS::CEE_DUP, ReaderBaseNS::CEE_POP,
ReaderBaseNS::CEE_JMP, ReaderBaseNS::CEE_CALL,
ReaderBaseNS::CEE_CALLI, ReaderBaseNS::CEE_RET,
ReaderBaseNS::CEE_BR_S, ReaderBaseNS::CEE_BRFALSE_S,
ReaderBaseNS::CEE_BRTRUE_S, ReaderBaseNS::CEE_BEQ_S,
ReaderBaseNS::CEE_BGE_S, ReaderBaseNS::CEE_BGT_S,
ReaderBaseNS::CEE_BLE_S, ReaderBaseNS::CEE_BLT_S,
ReaderBaseNS::CEE_BNE_UN_S, ReaderBaseNS::CEE_BGE_UN_S,
ReaderBaseNS::CEE_BGT_UN_S, ReaderBaseNS::CEE_BLE_UN_S,
ReaderBaseNS::CEE_BLT_UN_S, ReaderBaseNS::CEE_BR,
ReaderBaseNS::CEE_BRFALSE, ReaderBaseNS::CEE_BRTRUE,
ReaderBaseNS::CEE_BEQ, ReaderBaseNS::CEE_BGE,
ReaderBaseNS::CEE_BGT, ReaderBaseNS::CEE_BLE,
ReaderBaseNS::CEE_BLT, ReaderBaseNS::CEE_BNE_UN,
ReaderBaseNS::CEE_BGE_UN, ReaderBaseNS::CEE_BGT_UN,
ReaderBaseNS::CEE_BLE_UN, ReaderBaseNS::CEE_BLT_UN,
ReaderBaseNS::CEE_SWITCH, ReaderBaseNS::CEE_LDIND_I1,
ReaderBaseNS::CEE_LDIND_U1, ReaderBaseNS::CEE_LDIND_I2,
ReaderBaseNS::CEE_LDIND_U2, ReaderBaseNS::CEE_LDIND_I4,
ReaderBaseNS::CEE_LDIND_U4, ReaderBaseNS::CEE_LDIND_I8,
ReaderBaseNS::CEE_LDIND_I, ReaderBaseNS::CEE_LDIND_R4,
ReaderBaseNS::CEE_LDIND_R8, ReaderBaseNS::CEE_LDIND_REF,
ReaderBaseNS::CEE_STIND_REF, ReaderBaseNS::CEE_STIND_I1,
ReaderBaseNS::CEE_STIND_I2, ReaderBaseNS::CEE_STIND_I4,
ReaderBaseNS::CEE_STIND_I8, ReaderBaseNS::CEE_STIND_R4,
ReaderBaseNS::CEE_STIND_R8, ReaderBaseNS::CEE_ADD,
ReaderBaseNS::CEE_SUB, ReaderBaseNS::CEE_MUL,
ReaderBaseNS::CEE_DIV, ReaderBaseNS::CEE_DIV_UN,
ReaderBaseNS::CEE_REM, ReaderBaseNS::CEE_REM_UN,
ReaderBaseNS::CEE_AND, ReaderBaseNS::CEE_OR,
ReaderBaseNS::CEE_XOR, ReaderBaseNS::CEE_SHL,
ReaderBaseNS::CEE_SHR, ReaderBaseNS::CEE_SHR_UN,
ReaderBaseNS::CEE_NEG, ReaderBaseNS::CEE_NOT,
ReaderBaseNS::CEE_CONV_I1, ReaderBaseNS::CEE_CONV_I2,
ReaderBaseNS::CEE_CONV_I4, ReaderBaseNS::CEE_CONV_I8,
ReaderBaseNS::CEE_CONV_R4, ReaderBaseNS::CEE_CONV_R8,
ReaderBaseNS::CEE_CONV_U4, ReaderBaseNS::CEE_CONV_U8,
ReaderBaseNS::CEE_CALLVIRT, ReaderBaseNS::CEE_CPOBJ,
ReaderBaseNS::CEE_LDOBJ, ReaderBaseNS::CEE_LDSTR,
ReaderBaseNS::CEE_NEWOBJ, ReaderBaseNS::CEE_CASTCLASS,
ReaderBaseNS::CEE_ISINST, ReaderBaseNS::CEE_CONV_R_UN,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED58,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED1,
ReaderBaseNS::CEE_UNBOX, ReaderBaseNS::CEE_THROW,
ReaderBaseNS::CEE_LDFLD, ReaderBaseNS::CEE_LDFLDA,
ReaderBaseNS::CEE_STFLD, ReaderBaseNS::CEE_LDSFLD,
ReaderBaseNS::CEE_LDSFLDA, ReaderBaseNS::CEE_STSFLD,
ReaderBaseNS::CEE_STOBJ, ReaderBaseNS::CEE_CONV_OVF_I1_UN,
ReaderBaseNS::CEE_CONV_OVF_I2_UN, ReaderBaseNS::CEE_CONV_OVF_I4_UN,
ReaderBaseNS::CEE_CONV_OVF_I8_UN, ReaderBaseNS::CEE_CONV_OVF_U1_UN,
ReaderBaseNS::CEE_CONV_OVF_U2_UN, ReaderBaseNS::CEE_CONV_OVF_U4_UN,
ReaderBaseNS::CEE_CONV_OVF_U8_UN, ReaderBaseNS::CEE_CONV_OVF_I_UN,
ReaderBaseNS::CEE_CONV_OVF_U_UN, ReaderBaseNS::CEE_BOX,
ReaderBaseNS::CEE_NEWARR, ReaderBaseNS::CEE_LDLEN,
ReaderBaseNS::CEE_LDELEMA, ReaderBaseNS::CEE_LDELEM_I1,
ReaderBaseNS::CEE_LDELEM_U1, ReaderBaseNS::CEE_LDELEM_I2,
ReaderBaseNS::CEE_LDELEM_U2, ReaderBaseNS::CEE_LDELEM_I4,
ReaderBaseNS::CEE_LDELEM_U4, ReaderBaseNS::CEE_LDELEM_I8,
ReaderBaseNS::CEE_LDELEM_I, ReaderBaseNS::CEE_LDELEM_R4,
ReaderBaseNS::CEE_LDELEM_R8, ReaderBaseNS::CEE_LDELEM_REF,
ReaderBaseNS::CEE_STELEM_I, ReaderBaseNS::CEE_STELEM_I1,
ReaderBaseNS::CEE_STELEM_I2, ReaderBaseNS::CEE_STELEM_I4,
ReaderBaseNS::CEE_STELEM_I8, ReaderBaseNS::CEE_STELEM_R4,
ReaderBaseNS::CEE_STELEM_R8, ReaderBaseNS::CEE_STELEM_REF,
ReaderBaseNS::CEE_LDELEM, ReaderBaseNS::CEE_STELEM,
ReaderBaseNS::CEE_UNBOX_ANY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED5,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED6,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED7,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED9,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED10,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED11,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED12,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED13,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED14,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED15,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED16,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED17,
ReaderBaseNS::CEE_CONV_OVF_I1, ReaderBaseNS::CEE_CONV_OVF_U1,
ReaderBaseNS::CEE_CONV_OVF_I2, ReaderBaseNS::CEE_CONV_OVF_U2,
ReaderBaseNS::CEE_CONV_OVF_I4, ReaderBaseNS::CEE_CONV_OVF_U4,
ReaderBaseNS::CEE_CONV_OVF_I8, ReaderBaseNS::CEE_CONV_OVF_U8,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED50,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED18,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED19,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED20,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED21,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED22,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED23,
ReaderBaseNS::CEE_REFANYVAL, ReaderBaseNS::CEE_CKFINITE,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED24,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED25,
ReaderBaseNS::CEE_MKREFANY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED59,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED60,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED61,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED62,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED63,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED64,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED65,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED66,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED67,
ReaderBaseNS::CEE_LDTOKEN, ReaderBaseNS::CEE_CONV_U2,
ReaderBaseNS::CEE_CONV_U1, ReaderBaseNS::CEE_CONV_I,
ReaderBaseNS::CEE_CONV_OVF_I, ReaderBaseNS::CEE_CONV_OVF_U,
ReaderBaseNS::CEE_ADD_OVF, ReaderBaseNS::CEE_ADD_OVF_UN,
ReaderBaseNS::CEE_MUL_OVF, ReaderBaseNS::CEE_MUL_OVF_UN,
ReaderBaseNS::CEE_SUB_OVF, ReaderBaseNS::CEE_SUB_OVF_UN,
ReaderBaseNS::CEE_ENDFINALLY, ReaderBaseNS::CEE_LEAVE,
ReaderBaseNS::CEE_LEAVE_S, ReaderBaseNS::CEE_STIND_I,
ReaderBaseNS::CEE_CONV_U, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL,
ReaderBaseNS::CEE_ILLEGAL, ReaderBaseNS::CEE_ILLEGAL};
// Array which maps prefixed bytecode to WVM opcode.
static const ReaderBaseNS::OPCODE PrefixedByteCodes[33] = {
ReaderBaseNS::CEE_ARGLIST, ReaderBaseNS::CEE_CEQ,
ReaderBaseNS::CEE_CGT, ReaderBaseNS::CEE_CGT_UN,
ReaderBaseNS::CEE_CLT, ReaderBaseNS::CEE_CLT_UN,
ReaderBaseNS::CEE_LDFTN, ReaderBaseNS::CEE_LDVIRTFTN,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED56,
ReaderBaseNS::CEE_LDARG, ReaderBaseNS::CEE_LDARGA,
ReaderBaseNS::CEE_STARG, ReaderBaseNS::CEE_LDLOC,
ReaderBaseNS::CEE_LDLOCA, ReaderBaseNS::CEE_STLOC,
ReaderBaseNS::CEE_LOCALLOC,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED57,
ReaderBaseNS::CEE_ENDFILTER, ReaderBaseNS::CEE_UNALIGNED,
ReaderBaseNS::CEE_VOLATILE, ReaderBaseNS::CEE_TAILCALL,
ReaderBaseNS::CEE_INITOBJ, ReaderBaseNS::CEE_CONSTRAINED,
ReaderBaseNS::CEE_CPBLK, ReaderBaseNS::CEE_INITBLK,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED69,
ReaderBaseNS::CEE_RETHROW,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED51,
ReaderBaseNS::CEE_SIZEOF, ReaderBaseNS::CEE_REFANYTYPE,
ReaderBaseNS::CEE_READONLY,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED53,
ReaderBaseNS::CEE_ILLEGAL, // ReaderBaseNS::CEE_UNUSED54
};
#include "bytecodetowvmcode.def"
uint32_t ILCursor = ILOffset;
uint32_t OperandOffset = 0;
@ -555,8 +383,7 @@ uint32_t parseILOpcode(uint8_t *ILInput, uint32_t ILOffset, uint32_t ILSize,
// This is case (2): a switch opcode. Make sure we have at least four bytes
// remaining s.t. getMSILInstrLength can read the number of switch cases.
if (TheOpcode == ReaderBaseNS::CEE_SWITCH &&
(ILSize - ILCursor) < 4) {
if (TheOpcode == ReaderBaseNS::CEE_SWITCH && (ILSize - ILCursor) < 4) {
goto underflow;
}
@ -740,8 +567,7 @@ uint32_t ReaderBase::getCurrentMethodHash(void) {
return JitInfo->getMethodHash(getCurrentMethodHandle());
}
uint32_t
ReaderBase::getCurrentMethodAttribs(void) {
uint32_t ReaderBase::getCurrentMethodAttribs(void) {
return JitInfo->getMethodAttribs(getCurrentMethodHandle());
}
@ -813,10 +639,9 @@ int ReaderBase::appendClassName(char16_t **Buffer, int32_t *BufferLen,
bool IncludeNamespace, bool FullInst,
bool IncludeAssembly) {
int IntBufferLen = *BufferLen, Return;
Return = JitInfo->appendClassName((WCHAR **)Buffer, &IntBufferLen, Class,
IncludeNamespace ? TRUE : FALSE,
FullInst ? TRUE : FALSE,
IncludeAssembly ? TRUE : FALSE);
Return = JitInfo->appendClassName(
(WCHAR **)Buffer, &IntBufferLen, Class, IncludeNamespace ? TRUE : FALSE,
FullInst ? TRUE : FALSE, IncludeAssembly ? TRUE : FALSE);
*BufferLen = IntBufferLen;
return Return;
}
@ -827,8 +652,7 @@ GCLayout *ReaderBase::getClassGCLayout(CORINFO_CLASS_HANDLE Class) {
// Note that we round this computation up.
const uint32_t PointerSize = getPointerByteSize();
const uint32_t ClassSize = JitInfo->getClassSize(Class);
const uint32_t GcLayoutSize =
((ClassSize + PointerSize - 1) / PointerSize);
const uint32_t GcLayoutSize = ((ClassSize + PointerSize - 1) / PointerSize);
// Our internal data strcutures prepend the number of GC pointers
// before the struct. Therefore we add the size of the
@ -852,8 +676,7 @@ GCLayout *ReaderBase::getClassGCLayout(CORINFO_CLASS_HANDLE Class) {
return GCLayoutInfo;
}
uint32_t
ReaderBase::getClassAttribs(CORINFO_CLASS_HANDLE Class) {
uint32_t ReaderBase::getClassAttribs(CORINFO_CLASS_HANDLE Class) {
return JitInfo->getClassAttribs(Class);
}
@ -861,8 +684,7 @@ uint32_t ReaderBase::getClassSize(CORINFO_CLASS_HANDLE Class) {
return JitInfo->getClassSize(Class);
}
uint32_t
ReaderBase::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE Class) {
uint32_t ReaderBase::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE Class) {
// Class must be value (a non-primitive value class, a multibyte)
ASSERTNR(Class && (getClassAttribs(Class) & CORINFO_FLG_VALUECLASS));
@ -921,8 +743,8 @@ void ReaderBase::getClassType(CORINFO_CLASS_HANDLE Class, uint32_t ClassAttribs,
}
}
bool
ReaderBase::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE Class) {
bool ReaderBase::canInlineTypeCheckWithObjectVTable(
CORINFO_CLASS_HANDLE Class) {
return JitInfo->canInlineTypeCheckWithObjectVTable(Class);
}
@ -999,8 +821,7 @@ void ReaderBase::getFieldInfo(CORINFO_RESOLVED_TOKEN *ResolvedToken,
FieldInfo);
}
CorInfoType ReaderBase::getFieldInfo(CORINFO_CLASS_HANDLE Class,
uint32_t Ordinal,
uint32_t *FieldOffset,
uint32_t Ordinal, uint32_t *FieldOffset,
CORINFO_CLASS_HANDLE *FieldClass) {
CORINFO_FIELD_HANDLE Field;
@ -1128,8 +949,7 @@ const char *ReaderBase::getMethodName(CORINFO_METHOD_HANDLE Method,
}
// Find the attribs of the method handle
uint32_t
ReaderBase::getMethodAttribs(CORINFO_METHOD_HANDLE Method) {
uint32_t ReaderBase::getMethodAttribs(CORINFO_METHOD_HANDLE Method) {
return JitInfo->getMethodAttribs(Method);
}
@ -1186,8 +1006,8 @@ void ReaderBase::getMethodInfo(CORINFO_METHOD_HANDLE Method,
JitInfo->getMethodInfo(Method, Info);
}
void
ReaderBase::methodMustBeLoadedBeforeCodeIsRun(CORINFO_METHOD_HANDLE Method) {
void ReaderBase::methodMustBeLoadedBeforeCodeIsRun(
CORINFO_METHOD_HANDLE Method) {
JitInfo->methodMustBeLoadedBeforeCodeIsRun(Method);
}
@ -1556,7 +1376,8 @@ static int rgnRangeIsEnclosedInRegion(uint32_t StartOffset, uint32_t EndOffset,
that contains [StartOffset..EndOffset)
--*/
EHRegion *rgnFindLowestEnclosingRegion(EHRegion *RegionTree, uint32_t StartOffset,
EHRegion *rgnFindLowestEnclosingRegion(EHRegion *RegionTree,
uint32_t StartOffset,
uint32_t EndOffset) {
EHRegion *TryChild;
EHRegion *RetVal = nullptr;
@ -2059,29 +1880,13 @@ void ReaderBase::setupBlockForEH() {
}
void ReaderBase::fgFixRecursiveEdges(FlowGraphNode *HeadBlock) {
FlowGraphNode *Block, *FallThroughBlock;
IRNode *BranchNode, *LabelNode;
bool HasFallThrough;
HasFallThrough = false;
FallThroughBlock = nullptr;
// As a special case, localloc is incompatible with the recursive
// tail call optimization, and any branches that we initially set up
// for the recursive tail call (before we knew about the localloc)
// should instead be re-pointed at the fall-through (for tail.call)
// or the function exit (for jmp).
if (HasLocAlloc) {
// Revert all recursive branch IR.
// For a tail.call, this involves changing to fall-through.
// For a jmp, this involves changing to point at the exit label.
BranchList *BranchList, *BranchListNext;
for (BranchList = fgGetLabelBranchList(entryLabel()); BranchList != nullptr;
BranchList = BranchListNext) {
BranchListNext = branchListGetNext(BranchList);
BranchNode = branchListGetIRNode(BranchList);
fgRevertRecursiveBranch(BranchNode);
}
if (HasLocAlloc && HasOptimisticTailRecursionTransform) {
throw NotYetImplementedException("undo optimistic recursive tail calls");
}
}
@ -2121,7 +1926,7 @@ FlowGraphNode *ReaderBase::buildFlowGraph(FlowGraphNode **FgTail) {
// pointer to the new entry is then returned.
//
FlowGraphNodeOffsetList *ReaderBase::fgAddNodeMSILOffset(
FlowGraphNode **Node, // A pointer to FlowGraphNode* node
FlowGraphNode **Node, // A pointer to FlowGraphNode* node
uint32_t TargetOffset // The MSIL offset of the node
) {
FlowGraphNodeOffsetList *Element, *PreviousElement, *NewElement;
@ -2400,8 +2205,7 @@ bool ReaderBase::fgLeaveIsNonLocal(FlowGraphNode *Fg, uint32_t LeaveOffset,
(LeaveTarget >= rgnGetEndMSILOffset(CurrentRegion)))) {
if (LeaveOffset == rgnGetEndMSILOffset(CurrentRegion)) {
// We need to confirm whether this leave is going to the canonical place!
uint32_t CanonicalOffset =
fgGetRegionCanonicalExitOffset(CurrentRegion);
uint32_t CanonicalOffset = fgGetRegionCanonicalExitOffset(CurrentRegion);
if (LeaveTarget == CanonicalOffset) {
// Though this was an explicit goto which is to a nonlocal location,
// it is canonical and correct... therefore it doesn't need any
@ -2425,8 +2229,7 @@ bool ReaderBase::fgLeaveIsNonLocal(FlowGraphNode *Fg, uint32_t LeaveOffset,
// Actual flow graph manipulation is performed by FgSplitBlock,
// which is not common.
FlowGraphNode *ReaderBase::fgSplitBlock(FlowGraphNode *Block,
uint32_t CurrentOffset,
IRNode *Node) {
uint32_t CurrentOffset, IRNode *Node) {
FlowGraphNode *NewBlock;
uint32_t OldEndOffset;
@ -2563,7 +2366,7 @@ void ReaderBase::fgReplaceBranchTargets() {
// patched up to match the region info of the inserted node.
void ReaderBase::fgInsertBeginRegionExceptionNode(
uint32_t Offset, // This is the offset where you want Node to be
IRNode *Node // This is our actual EH end node (OPTRY, etc.)
IRNode *Node // This is our actual EH end node (OPTRY, etc.)
) {
FlowGraphNode *Block;
@ -2635,7 +2438,7 @@ void ReaderBase::fgInsertBeginRegionExceptionNode(
// and modifies the flow graph if necesary.
void ReaderBase::fgInsertEndRegionExceptionNode(
uint32_t Offset, // This is the offset where you want Node to be
IRNode *Node // This is our actual EH End node
IRNode *Node // This is our actual EH End node
) {
FlowGraphNode *Block;
@ -2678,8 +2481,8 @@ void ReaderBase::fgInsertEndRegionExceptionNode(
}
}
void
ReaderBase::fgEnsureEnclosingRegionBeginsWithLabel(IRNode *HandlerStartNode) {
void ReaderBase::fgEnsureEnclosingRegionBeginsWithLabel(
IRNode *HandlerStartNode) {
EHRegion *HandlerRegion, *TryRegion;
IRNode *HandlerLabelNode, *ExceptNode;
@ -3098,10 +2901,8 @@ void ReaderBase::fgBuildPhase1(FlowGraphNode *Block, uint8_t *ILInput,
// last instruction (asycronous flow can target this)
LegalTargetOffsets->allocateBitVector(ILInputSize + 1, this);
GvStackPush =
(uint16_t *)getTempMemory(ILInputSize * sizeof(uint16_t));
GvStackPop =
(uint16_t *)getTempMemory(ILInputSize * sizeof(uint16_t));
GvStackPush = (uint16_t *)getTempMemory(ILInputSize * sizeof(uint16_t));
GvStackPop = (uint16_t *)getTempMemory(ILInputSize * sizeof(uint16_t));
StackOffset = 0;
}
@ -3194,8 +2995,8 @@ void ReaderBase::fgBuildPhase1(FlowGraphNode *Block, uint8_t *ILInput,
// a protected region. If it's outside of a region
// it acts like a branch.
if ((Opcode == ReaderBaseNS::CEE_LEAVE ||
Opcode == ReaderBaseNS::CEE_LEAVE_S)
&& (EhRegionTree != nullptr)) {
Opcode == ReaderBaseNS::CEE_LEAVE_S) &&
(EhRegionTree != nullptr)) {
const char *FailReason = nullptr;
TargetOffset = updateLeaveOffset(EhRegionTree, CurrentOffset,
TargetOffset, &FailReason);
@ -3335,8 +3136,8 @@ void ReaderBase::fgBuildPhase1(FlowGraphNode *Block, uint8_t *ILInput,
// Make/insert end finally
BlockNode = fgNodeGetStartIRNode(Block);
BranchNode = fgMakeEndFinallyHelper(BlockNode, CurrentOffset,
IsLexicalEnd);
BranchNode =
fgMakeEndFinallyHelper(BlockNode, CurrentOffset, IsLexicalEnd);
// And split the block
fgNodeSetEndMSILOffset(Block, NextOffset);
@ -3676,8 +3477,8 @@ void ReaderBase::verifyRecordBranchForVerification(IRNode *Branch,
/// \param BufferSize The length of the buffer in bytes.
///
/// \returns FlowGraphNode corresponding to the bytes.
FlowGraphNode *
ReaderBase::fgBuildBasicBlocksFromBytes(uint8_t *Buffer, uint32_t BufferSize) {
FlowGraphNode *ReaderBase::fgBuildBasicBlocksFromBytes(uint8_t *Buffer,
uint32_t BufferSize) {
FlowGraphNode *Block;
// Initialize head block to root region.
@ -4066,17 +3867,17 @@ IRNode *ReaderBase::loadIndir(ReaderBaseNS::LdIndirOpcode Opcode,
bool IsVolatile, bool IsInterfReadOnly,
bool AddressMayBeNull) {
static const CorInfoType Map[ReaderBaseNS::LastLdindOpcode] = {
CORINFO_TYPE_BYTE, // STIND_I1
CORINFO_TYPE_UBYTE, // STIND_U1
CORINFO_TYPE_SHORT, // STIND_I2
CORINFO_TYPE_USHORT, // STIND_U2
CORINFO_TYPE_INT, // STIND_I4
CORINFO_TYPE_UINT, // STIND_U4
CORINFO_TYPE_LONG, // STIND_I8
CORINFO_TYPE_NATIVEINT, // STIND_I
CORINFO_TYPE_FLOAT, // STIND_R4
CORINFO_TYPE_DOUBLE, // STIND_R8
CORINFO_TYPE_REFANY // STIND_REF
CORINFO_TYPE_BYTE, // LDIND_I1
CORINFO_TYPE_UBYTE, // LDIND_U1
CORINFO_TYPE_SHORT, // LDIND_I2
CORINFO_TYPE_USHORT, // LDIND_U2
CORINFO_TYPE_INT, // LDIND_I4
CORINFO_TYPE_UINT, // LDIND_U4
CORINFO_TYPE_LONG, // LDIND_I8
CORINFO_TYPE_NATIVEINT, // LDIND_I
CORINFO_TYPE_FLOAT, // LDIND_R4
CORINFO_TYPE_DOUBLE, // LDIND_R8
CORINFO_TYPE_REFANY // LDIND_REF
};
ASSERTNR(Opcode >= ReaderBaseNS::LdindI1 &&
@ -4688,7 +4489,7 @@ ReaderBase::rdrGetStaticFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
// Record (def) instruction that holds shared statics base
domInfoRecordSharedStaticBaseDefine(CurrentFgNode, HelperId, Class,
SharedStaticsBaseNode);
SharedStaticsBaseNode);
}
}
@ -5065,7 +4866,7 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode,
#ifndef CC_PEVERIFY
// An intrinsic! Ask if client would like to expand it.
if ((Data->getMethodAttribs() & CORINFO_FLG_INTRINSIC)
// if we're going to have to mess around with Args don't bother
// if we're going to have to mess around with Args don't bother
&&
(!Data->hasThis() ||
Data->getCallInfo()->thisTransform == CORINFO_NO_THIS_TRANSFORM)) {
@ -5770,8 +5571,8 @@ ReaderBase::rdrGetDelegateInvokeTarget(ReaderCallTargetData *CallTargetData,
return derefAddress(AddressNode, false, true);
}
bool
ReaderBase::rdrCallIsDelegateConstruct(ReaderCallTargetData *CallTargetData) {
bool ReaderBase::rdrCallIsDelegateConstruct(
ReaderCallTargetData *CallTargetData) {
if (CallTargetData->isNewObj()) {
uint32_t ClassAttribs = CallTargetData->getClassAttribs();
uint32_t MethodAttribs = CallTargetData->getMethodAttribs();
@ -5817,8 +5618,7 @@ void ReaderBase::clearStack() {
}
}
void ReaderBase::initParamsAndAutos(uint32_t NumParam,
uint32_t NumAuto) {
void ReaderBase::initParamsAndAutos(uint32_t NumParam, uint32_t NumAuto) {
// Init verification maps
if (VerificationNeeded) {
NumVerifyParams = NumParam;
@ -6278,9 +6078,8 @@ void ReaderBase::domInfoRecordSharedStaticBaseDefine(
// Returns whether particular class has already been initialized
// by current block, or any of its dominators.
bool
ReaderBase::domInfoDominatorHasClassInit(FlowGraphNode *Fg,
CORINFO_CLASS_HANDLE ClassHandle) {
bool ReaderBase::domInfoDominatorHasClassInit(
FlowGraphNode *Fg, CORINFO_CLASS_HANDLE ClassHandle) {
if (generateDebugCode())
return false;
@ -6377,8 +6176,7 @@ bool ReaderBase::isUnmarkedTailCall(uint8_t *ILInput, uint32_t ILInputSize,
//
// NOTE: Other necessary checks are performed later
bool ReaderBase::isUnmarkedTailCallHelper(uint8_t *ILInput,
uint32_t ILInputSize,
uint32_t Offset,
uint32_t ILInputSize, uint32_t Offset,
mdToken Token) {
// Get the next instruction (if any)
uint8_t *UnusedOperand;
@ -6542,8 +6340,8 @@ void ReaderBase::readBytesForFlowGraphNodeHelper(
#endif
ReaderBaseNS::OPCODE PrevOp = Opcode;
NextOffset = parseILOpcode(ILInput, CurrentOffset, ILSize, this, &Opcode,
&Operand);
NextOffset =
parseILOpcode(ILInput, CurrentOffset, ILSize, this, &Opcode, &Operand);
CurrInstrOffset = CurrentOffset;
NextInstrOffset = NextOffset;
@ -8074,7 +7872,7 @@ void ReaderBase::msilToIR(void) {
// Set up the initial stack
ReaderOperandStack = createStack(
std::min(MethodInfo->maxStack, std::min(100u, MethodInfo->ILCodeSize)),
std::min(MethodInfo->maxStack, std::min(100u, MethodInfo->ILCodeSize)),
this);
ASSERTNR(ReaderOperandStack);
fgNodeSetOperandStack(FgHead, ReaderOperandStack);
@ -8298,8 +8096,7 @@ void ReaderCallTargetData::resetReader(ReaderBase *Reader) {
ASSERTNR(!IsOptimizedDelegateCtor);
}
uint32_t
ReaderCallTargetData::getClassAttribs() {
uint32_t ReaderCallTargetData::getClassAttribs() {
if (!AreClassAttribsValid) {
TargetClassAttribs = Reader->getClassAttribs(getClassHandle());
AreClassAttribsValid = true;
@ -8529,9 +8326,9 @@ void ReaderCallTargetData::setOptimizedDelegateCtor(
void ReaderCallTargetData::init(
ReaderBase *Reader, mdToken TargetToken, mdToken ConstraintToken,
mdToken LoadFtnToken, bool IsTailCall, bool IsUnmarkedTailCall,
bool IsReadonlyCall, ReaderBaseNS::CallOpcode Opcode,
uint32_t MsilOffset, CORINFO_CONTEXT_HANDLE Context,
CORINFO_MODULE_HANDLE Scope, CORINFO_METHOD_HANDLE Caller) {
bool IsReadonlyCall, ReaderBaseNS::CallOpcode Opcode, uint32_t MsilOffset,
CORINFO_CONTEXT_HANDLE Context, CORINFO_MODULE_HANDLE Scope,
CORINFO_METHOD_HANDLE Caller) {
this->Reader = Reader;
this->LoadFtnToken = LoadFtnToken;

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

@ -50,7 +50,7 @@ IRNode *GenStack::pop() {
if (size() == 0)
LLILCJit::fatal(CORJIT_BADCODE);
IRNode* result = Stack.back();
IRNode *result = Stack.back();
Stack.pop_back();
return result;
}
@ -73,7 +73,7 @@ ReaderStack *GenStack::copy() {
GenStack *Copy;
void *Buffer = Reader->getTempMemory(sizeof(GenStack));
Copy = new (Buffer)GenStack(Stack.capacity() + 1, Reader);
Copy = new (Buffer) GenStack(Stack.capacity() + 1, Reader);
for (auto Value : *this) {
Copy->push(Value);
}
@ -83,7 +83,7 @@ ReaderStack *GenStack::copy() {
ReaderStack *GenIR::createStack(uint32_t MaxStack, ReaderBase *Reader) {
void *Buffer = Reader->getTempMemory(sizeof(GenStack));
// extra 16 should reduce frequency of reallocation when inlining / jmp
return new (Buffer)GenStack(MaxStack + 16, Reader);
return new (Buffer) GenStack(MaxStack + 16, Reader);
}
#pragma endregion
@ -332,12 +332,11 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
}
// TODO: support for JustMyCode hook
if ((JitFlags & CORJIT_FLG_DEBUG_CODE) &&
!(JitFlags & CORJIT_FLG_IL_STUB)) {
if ((JitFlags & CORJIT_FLG_DEBUG_CODE) && !(JitFlags & CORJIT_FLG_IL_STUB)) {
bool IsIndirect = false;
void * DebugHandle =
getJustMyCodeHandle(getCurrentMethodHandle(), &IsIndirect);
void *DebugHandle =
getJustMyCodeHandle(getCurrentMethodHandle(), &IsIndirect);
if (DebugHandle != nullptr) {
throw NotYetImplementedException("just my code hook");
@ -355,7 +354,7 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
initClass(nullptr, getCurrentMethodHandle(), getCurrentContext());
const bool InitClass = InitResult & CORINFO_INITCLASS_USE_HELPER;
if (InitClass) {
throw NotYetImplementedException("init class");
throw NotYetImplementedException("init class");
}
}
@ -554,6 +553,14 @@ IRNode *GenIR::instParam() {
return (IRNode *)TypeParameter;
}
// Convert ReaderAlignType to byte alighnment
uint32_t GenIR::convertReaderAlignment(ReaderAlignType ReaderAlignment) {
uint32_t Result = (ReaderAlignment == Reader_AlignNatural)
? TargetPointerSizeInBits / 8
: ReaderAlignment;
return Result;
}
#pragma endregion
#pragma region DIAGNOSTICS
@ -679,8 +686,8 @@ void GenIR::verifyStaticAlignment(void *FieldAddress, CorInfoType CorType,
break;
}
// TODO: the commented out parts depend on debug code
// which we haven't ported.
// TODO: the commented out parts depend on debug code
// which we haven't ported.
#if defined(_DEBUG)
if (AlignmentError /*&& ifdb(DB_UNALIGNEDSTATICASSERT)*/) {
/*dbgs() << format
@ -1166,23 +1173,20 @@ Type *GenIR::getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
ByteOffset += DataLayout->getTypeSizeInBits(ArrayPadTy) / 8;
}
// For arrays of ref classes there's an array element
// type.
CORINFO_CLASS_HANDLE ArrayElementHandle = nullptr;
CorInfoType ArrayElementCorTy =
getChildType(ClassHandle, &ArrayElementHandle);
if (ArrayElementCorTy == CORINFO_TYPE_CLASS) {
Type *ArrayElementFieldTy =
Type::getIntNPtrTy(LLVMContext, TargetPointerSizeInBits);
Fields.push_back(ArrayElementFieldTy);
ByteOffset += DataLayout->getTypeSizeInBits(ArrayElementFieldTy) / 8;
}
Type *ElementTy = getType(ArrayElementCorTy, ArrayElementHandle);
// Next comes the array of elements. Nominally 0 size so no
// ByteOffset update.
//
// Verify that the offset we calculated matches the expected offset
// for arrays of objects.
if (ArrayElementCorTy == CORINFO_TYPE_CLASS) {
ASSERTNR(ByteOffset == JitContext->EEInfo.offsetOfObjArrayData);
}
// TODO: There may be some inter-element padding here for arrays
// of value classes.
Type *ArrayOfElementTy = ArrayType::get(ElementTy, 0);
@ -1403,6 +1407,7 @@ uint32_t GenIR::stackSize(CorInfoType CorType) {
case CorInfoType::CORINFO_TYPE_NATIVEUINT:
case CorInfoType::CORINFO_TYPE_PTR:
case CorInfoType::CORINFO_TYPE_BYREF:
case CorInfoType::CORINFO_TYPE_CLASS:
return TargetPointerSizeInBits;
default:
@ -1439,6 +1444,7 @@ uint32_t GenIR::size(CorInfoType CorType) {
case CorInfoType::CORINFO_TYPE_NATIVEUINT:
case CorInfoType::CORINFO_TYPE_PTR:
case CorInfoType::CORINFO_TYPE_BYREF:
case CorInfoType::CORINFO_TYPE_CLASS:
return TargetPointerSizeInBits;
default:
@ -1462,6 +1468,7 @@ bool GenIR::isSigned(CorInfoType CorType) {
case CorInfoType::CORINFO_TYPE_NATIVEUINT:
case CorInfoType::CORINFO_TYPE_PTR:
case CorInfoType::CORINFO_TYPE_BYREF:
case CorInfoType::CORINFO_TYPE_CLASS:
return false;
case CorInfoType::CORINFO_TYPE_BYTE:
@ -1687,7 +1694,7 @@ FlowGraphNode *GenIR::fgSplitBlock(FlowGraphNode *Block, IRNode *Node) {
BasicBlock *NewBlock;
if (Inst == nullptr) {
NewBlock = BasicBlock::Create(*JitContext->LLVMContext, "", Function,
TheBasicBlock->getNextNode());
TheBasicBlock->getNextNode());
TerminatorInst *TermInst = TheBasicBlock->getTerminator();
if (TermInst != nullptr) {
if (isa<UnreachableInst>(TermInst)) {
@ -1708,7 +1715,16 @@ FlowGraphNode *GenIR::fgSplitBlock(FlowGraphNode *Block, IRNode *Node) {
BranchInst::Create(NewBlock, TheBasicBlock);
}
} else {
NewBlock = TheBasicBlock->splitBasicBlock(Inst);
if (TheBasicBlock->getTerminator() != nullptr) {
NewBlock = TheBasicBlock->splitBasicBlock(Inst);
} else {
NewBlock = BasicBlock::Create(*JitContext->LLVMContext, "", Function,
TheBasicBlock->getNextNode());
NewBlock->getInstList().splice(NewBlock->end(),
TheBasicBlock->getInstList(), Inst,
TheBasicBlock->end());
BranchInst::Create(NewBlock, TheBasicBlock);
}
}
return (FlowGraphNode *)NewBlock;
}
@ -1730,7 +1746,7 @@ void GenIR::fgDeleteNodesFromBlock(FlowGraphNode *Node) {
IRNode *GenIR::fgMakeSwitch(IRNode *DefaultLabel, IRNode *Insert) {
LLVMBuilder->SetInsertPoint((BasicBlock *)Insert);
// Create switch with null condition because it is invoked during
// Create switch with null condition because it is invoked during
// flow-graph build. The subsequent pass of Reader will set
// this operanad properly.
return (IRNode *)LLVMBuilder->CreateSwitch(loadNull(),
@ -1740,7 +1756,7 @@ IRNode *GenIR::fgMakeSwitch(IRNode *DefaultLabel, IRNode *Insert) {
IRNode *GenIR::fgAddCaseToCaseList(IRNode *SwitchNode, IRNode *LabelNode,
unsigned Element) {
ConstantInt *Case = ConstantInt::get(*JitContext->LLVMContext,
APInt(32, (uint64_t)Element, false));
APInt(32, (uint64_t)Element, false));
((SwitchInst *)SwitchNode)->addCase(Case, (BasicBlock *)LabelNode);
return SwitchNode;
}
@ -2405,7 +2421,7 @@ GenIR::loadManagedAddress(const std::vector<Value *> &UnmanagedAddresses,
ManagedPointerType);
}
// Load the address of the field described by pResolvedToken
// Load the address of the field described by ResolvedToken
// from the object Obj.
IRNode *GenIR::loadFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
IRNode *Obj) {
@ -2424,7 +2440,7 @@ IRNode *GenIR::loadFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
return Result;
}
// Get the address of the field described by pResolvedToken
// Get the address of the field described by ResolvedToken
// from the object Obj. Optionally null check.
IRNode *GenIR::getFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken,
CORINFO_FIELD_INFO *FieldInfo, IRNode *Obj,
@ -2524,22 +2540,49 @@ IRNode *GenIR::loadField(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Obj,
IRNode *Address =
getFieldAddress(ResolvedToken, &FieldInfo, Obj, NullCheckBeforeLoad);
if (FieldTy->isStructTy()) {
return loadAtAddress(Address, FieldTy, CorInfoType, ResolvedToken,
AlignmentPrefix, IsVolatile, !NullCheckBeforeLoad);
}
// Generate instructions for loading value of the specified type at the
// specified address.
IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType AlignmentPrefix, bool IsVolatile,
bool AddressMayBeNull) {
if (Ty->isStructTy()) {
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile, true,
!NullCheckBeforeLoad);
AddressMayBeNull);
} else {
LoadInst *LoadInst = makeLoad(Address, IsVolatile, !NullCheckBeforeLoad);
uint32_t Align = (AlignmentPrefix == Reader_AlignNatural)
? TargetPointerSizeInBits / 8
: AlignmentPrefix;
LoadInst *LoadInst = makeLoad(Address, IsVolatile, AddressMayBeNull);
uint32_t Align = convertReaderAlignment(AlignmentPrefix);
LoadInst->setAlignment(Align);
IRNode *Result = convertToStackType((IRNode *)LoadInst, CorInfoType);
IRNode *Result = convertToStackType((IRNode *)LoadInst, CorType);
return Result;
}
}
// Generate instructions for storing value of the specified type at the
// specified address.
void GenIR::storeAtAddress(IRNode *Address, IRNode *ValueToStore, Type *Ty,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
ReaderAlignType Alignment, bool IsVolatile,
bool IsField, bool AddressMayBeNull) {
// We do things differently based on whether the field is a value class.
if (Ty->isStructTy()) {
storeObj(ResolvedToken, ValueToStore, Address, Alignment, IsVolatile,
IsField, AddressMayBeNull);
}
else {
StoreInst *StoreInst = makeStore(ValueToStore, Address, IsVolatile,
AddressMayBeNull);
uint32_t Align = convertReaderAlignment(Alignment);
StoreInst->setAlignment(Align);
}
}
void GenIR::storeField(CORINFO_RESOLVED_TOKEN *FieldToken, IRNode *ValueToStore,
IRNode *Object, ReaderAlignType Alignment,
bool IsVolatile) {
@ -2602,21 +2645,9 @@ void GenIR::storeField(CORINFO_RESOLVED_TOKEN *FieldToken, IRNode *ValueToStore,
return;
}
// We do things differently based on whether the field is a value class.
if (!IsStructTy) {
makeStore(ValueToStore, Address, IsVolatile, !NullCheckBeforeStore);
return;
} else {
// The WVM lowerer cannot handle multi-byte indirs whose base pointer
// is the address of a field.
if (FieldCorType == CORINFO_TYPE_VALUECLASS ||
FieldCorType == CORINFO_TYPE_REFANY) {
Alignment = getMinimumClassAlignment(FieldClassHandle, Alignment);
}
storeObj(FieldToken, ValueToStore, Address, Alignment, IsVolatile, true,
!NullCheckBeforeStore);
return;
}
bool IsField = true;
return storeAtAddress(Address, ValueToStore, FieldTy, FieldToken, Alignment,
IsVolatile, IsField, !NullCheckBeforeStore);
}
void GenIR::storePrimitiveType(IRNode *Value, IRNode *Addr,
@ -2694,7 +2725,7 @@ void GenIR::storeStaticField(CORINFO_RESOLVED_TOKEN *FieldToken,
// If the runtime asks us to use a helper for the store, do so.
const bool NeedsWriteBarrier =
JitContext->JitInfo->isWriteBarrierHelperRequired(FieldHandle);
JitContext->JitInfo->isWriteBarrierHelperRequired(FieldHandle);
if (NeedsWriteBarrier) {
// Statics are always on the heap, so we can use an unchecked write barrier
rdrCallWriteBarrierHelper((IRNode *)Address, ValueToStore,
@ -2768,6 +2799,181 @@ IRNode *GenIR::addressOfLeaf(IRNode *Leaf) {
throw NotYetImplementedException("AddressOfLeaf");
}
IRNode *GenIR::loadElem(ReaderBaseNS::LdElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
IRNode *Array) {
static const CorInfoType Map[ReaderBaseNS::LastLdelemOpcode] = {
CorInfoType::CORINFO_TYPE_BYTE, // LDELEM_I1
CorInfoType::CORINFO_TYPE_UBYTE, // LDELEM_U1
CorInfoType::CORINFO_TYPE_SHORT, // LDELEM_I2
CorInfoType::CORINFO_TYPE_USHORT, // LDELEM_U2
CorInfoType::CORINFO_TYPE_INT, // LDELEM_I4
CorInfoType::CORINFO_TYPE_UINT, // LDELEM_U4
CorInfoType::CORINFO_TYPE_LONG, // LDELEM_I8
CorInfoType::CORINFO_TYPE_NATIVEINT, // LDELEM_I
CorInfoType::CORINFO_TYPE_FLOAT, // LDELEM_R4
CorInfoType::CORINFO_TYPE_DOUBLE, // LDELEM_R8
CorInfoType::CORINFO_TYPE_CLASS, // LDELEM_REF
CorInfoType::CORINFO_TYPE_UNDEF // LDELEM
};
ASSERTNR(Opcode >= ReaderBaseNS::LdelemI1 &&
Opcode < ReaderBaseNS::LastLdelemOpcode);
CorInfoType CorType = Map[Opcode];
ReaderAlignType Alignment = Reader_AlignNatural;
// ResolvedToken is only valid for ldelem.
if (Opcode != ReaderBaseNS::Ldelem) {
ResolvedToken = nullptr;
}
Type *ElementTy = getArrayElementType(Array, ResolvedToken, &CorType,
&Alignment);
Value *ElementAddress = genArrayElemAddress(Array, Index, ElementTy);
bool IsVolatile = false;
return loadAtAddressNonNull((IRNode *)ElementAddress, ElementTy, CorType,
ResolvedToken, Alignment, IsVolatile);
}
IRNode *GenIR::loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index,
IRNode *Array, bool IsReadOnly) {
ASSERTNR(ResolvedToken != nullptr);
CORINFO_CLASS_HANDLE ClassHandle = ResolvedToken->hClass;
uint32_t ClassAttribs = getClassAttribs(ClassHandle);
CorInfoType CorInfoType = JitContext->JitInfo->asCorInfoType(ClassHandle);
Type *ElementTy = getType(CorInfoType, ClassHandle);
// Attempt to use a helper call.
// We can only use the LDELEMA helper if the array elements
// are not value classes and the access is not readonly.
if (!IsReadOnly && ((ClassAttribs & CORINFO_FLG_VALUECLASS) == 0)) {
IRNode *HandleNode = genericTokenToNode(ResolvedToken);
PointerType *ElementAddressTy = getManagedPointerType(ElementTy);
return callHelperImpl(CORINFO_HELP_LDELEMA_REF, ElementAddressTy, Array,
Index, HandleNode);
}
return (IRNode *)genArrayElemAddress(Array, Index, ElementTy);
}
void GenIR::storeElem(ReaderBaseNS::StElemOpcode Opcode,
CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ValueToStore, IRNode *Index,
IRNode *Array) {
static const CorInfoType Map[ReaderBaseNS::LastStelemOpcode] = {
CorInfoType::CORINFO_TYPE_NATIVEINT, // STELEM_I
CorInfoType::CORINFO_TYPE_BYTE, // STELEM_I1
CorInfoType::CORINFO_TYPE_SHORT, // STELEM_I2
CorInfoType::CORINFO_TYPE_INT, // STELEM_I4
CorInfoType::CORINFO_TYPE_LONG, // STELEM_I8
CorInfoType::CORINFO_TYPE_FLOAT, // STELEM_R4
CorInfoType::CORINFO_TYPE_DOUBLE, // STELEM_R8
CorInfoType::CORINFO_TYPE_CLASS, // STELEM_REF
CorInfoType::CORINFO_TYPE_UNDEF // STELEM
};
ASSERTNR(Opcode >= ReaderBaseNS::StelemI &&
Opcode < ReaderBaseNS::LastStelemOpcode);
CorInfoType CorType = Map[Opcode];
ReaderAlignType Alignment = Reader_AlignNatural;
// ResolvedToken is only valid for stelem.
if (Opcode != ReaderBaseNS::Stelem) {
ResolvedToken = nullptr;
}
Type *ElementTy = getArrayElementType(Array, ResolvedToken, &CorType,
&Alignment);
if (CorType == CorInfoType::CORINFO_TYPE_CLASS) {
Constant *ConstantValue = dyn_cast<Constant>(ValueToStore);
if (ConstantValue == nullptr || !ConstantValue->isNullValue()) {
// This will call a helper that stores an element of object array with
// type checking. It will also call a write barrier if necessary. Storing
// null is always legal, doesn't need a write barrier, and thus does not
// need a helper call.
return storeElemRefAny(ValueToStore, Index, Array);
}
}
Value *ElementAddress = genArrayElemAddress(Array, Index, ElementTy);
bool IsVolatile = false;
bool IsField = false;
ValueToStore = convertFromStackType(ValueToStore, CorType, ElementTy);
if (ElementTy->isStructTy()) {
bool IsNonValueClass = false;
bool IsValueIsPointer = false;
bool IsUnchecked = false;
// Store with a write barrier if the struct has gc pointers.
rdrCallWriteBarrierHelper(Array, ValueToStore, Alignment, IsVolatile,
ResolvedToken, IsNonValueClass, IsValueIsPointer,
IsField, IsUnchecked);
}
else {
storeAtAddressNonNull((IRNode *)ElementAddress, ValueToStore,
ElementTy, ResolvedToken, Alignment, IsVolatile,
IsField);
}
}
// Get array element type.
Type *GenIR::getArrayElementType(IRNode *Array,
CORINFO_RESOLVED_TOKEN *ResolvedToken,
CorInfoType *CorType,
ReaderAlignType *Alignment) {
ASSERTNR(Alignment != nullptr);
ASSERTNR(CorType != nullptr);
CORINFO_CLASS_HANDLE ClassHandle = nullptr;
if (*CorType == CorInfoType::CORINFO_TYPE_CLASS) {
PointerType *Ty = cast<PointerType>(Array->getType());
StructType *ReferentTy = cast<StructType>(Ty->getPointerElementType());
unsigned int NumElements = ReferentTy->getNumElements();
ArrayType *ArrayTy =
cast<ArrayType>(ReferentTy->getElementType(NumElements - 1));
return ArrayTy->getElementType();
}
if (ResolvedToken != nullptr) {
ClassHandle = ResolvedToken->hClass;
*CorType = JitContext->JitInfo->asCorInfoType(ClassHandle);
if ((*CorType == CorInfoType::CORINFO_TYPE_VALUECLASS) ||
(*CorType == CORINFO_TYPE_REFANY)) {
*Alignment = getMinimumClassAlignment(ClassHandle, Reader_AlignNatural);
}
}
ASSERTNR(*CorType != CorInfoType::CORINFO_TYPE_UNDEF);
return getType(*CorType, ClassHandle);
}
// Get address of the array element.
Value *GenIR::genArrayElemAddress(IRNode *Array, IRNode *Index,
Type *ElementTy) {
// This call will load the array length which will ensure that the array is
// not null.
Array = genBoundsCheck(Array, Index);
PointerType *Ty = cast<PointerType>(Array->getType());
StructType *ReferentTy = cast<StructType>(Ty->getPointerElementType());
unsigned int RawArrayStructFieldIndex = ReferentTy->getNumElements() - 1;
Type *ArrayTy = ReferentTy->getElementType(RawArrayStructFieldIndex);
ASSERTNR(ArrayTy->isArrayTy());
ASSERTNR(ArrayTy->getArrayElementType() == ElementTy);
LLVMContext &Context = *this->JitContext->LLVMContext;
// Build up gep indices:
// the first index is for the struct representing the array;
// the second index is for the raw array (last field of the struct):
// the third index is for the array element.
Value *Indices[] = {
ConstantInt::get(Type::getInt32Ty(Context), 0),
ConstantInt::get(Type::getInt32Ty(Context), RawArrayStructFieldIndex),
Index};
return LLVMBuilder->CreateInBoundsGEP(Array, Indices);
}
void GenIR::branch() {
TerminatorInst *TermInst = LLVMBuilder->GetInsertBlock()->getTerminator();
ASSERT(TermInst != nullptr);
@ -2930,6 +3136,7 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
IRNode *Call = nullptr, *ReturnNode = nullptr;
IRNode *TargetNode = CallTargetInfo->getCallTargetNode();
CORINFO_SIG_INFO *SigInfo = CallTargetInfo->getSigInfo();
CORINFO_CALL_INFO *CallInfo = CallTargetInfo->getCallInfo();
unsigned HiddenMBParamSize = 0;
GCLayout *GCInfo = nullptr;
@ -2946,6 +3153,12 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
throw NotYetImplementedException("Call HasTypeArg");
}
if ((CallInfo != nullptr) && (CallInfo->kind == CORINFO_VIRTUALCALL_STUB)) {
// VSD calls have a special calling convention that requires the pointer
// to the stub in a target-specific register.
throw NotYetImplementedException("virtual stub dispatch");
}
// Ask GenIR to create return value.
if (!CallTargetInfo->isNewObj()) {
ReturnNode = makeCallReturnNode(SigInfo, &HiddenMBParamSize, &GCInfo);
@ -2966,7 +3179,8 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo,
if (I == 0) {
if (CallTargetInfo->isNewObj()) {
// Memory and a representative node for the 'this' pointer for newobj
// has not been created yet. Pass a null value of the right type for now;
// has not been created yet. Pass a null value of the right type for
// now;
// it will be replaced by the real value in canonNewObjCall.
ASSERT(ArgNode == nullptr);
ArgNode = (IRNode *)Constant::getNullValue(ArgType);
@ -3538,14 +3752,14 @@ bool GenIR::memoryBarrier() {
}
void GenIR::switchOpcode(IRNode *Opr) {
// We split the block right after the switch during the flow-graph build.
// The terminator is switch instruction itself.
// Now condition operand is updated.
BasicBlock *CurrBlock = LLVMBuilder->GetInsertBlock();
TerminatorInst *TermInst = CurrBlock->getTerminator();
SwitchInst *SwitchInstruction = cast<SwitchInst>(TermInst);
// We split the block right after the switch during the flow-graph build.
// The terminator is switch instruction itself.
// Now condition operand is updated.
BasicBlock *CurrBlock = LLVMBuilder->GetInsertBlock();
TerminatorInst *TermInst = CurrBlock->getTerminator();
SwitchInst *SwitchInstruction = cast<SwitchInst>(TermInst);
SwitchInstruction->setCondition(Opr);
SwitchInstruction->setCondition(Opr);
}
void GenIR::throwOpcode(IRNode *Arg1) {
@ -3558,7 +3772,9 @@ void GenIR::throwOpcode(IRNode *Arg1) {
ThrowCall->setDoesNotReturn();
}
IRNode *GenIR::genNullCheck(IRNode *Node) {
// Generate a call to the throw helper if the condition is met.
void GenIR::genConditionalThrow(Value *Condition, CorInfoHelpFunc HelperId,
const Twine &ThrowBlockName) {
BasicBlock *CheckBlock = LLVMBuilder->GetInsertBlock();
BasicBlock::iterator InsertPoint = LLVMBuilder->GetInsertPoint();
Instruction *NextInstruction =
@ -3566,39 +3782,33 @@ IRNode *GenIR::genNullCheck(IRNode *Node) {
// Create the throw block so we can reference it later.
// Note: we could generate much smaller IR by reusing the same throw block for
// all null checks, but at the cost of not being able to tell in a debugger
// what was null. The current strategy is to favor debuggability.
// all throws of the same kind, but at the cost of not being able to tell in a
// debugger which check caused the exception. The current strategy is to
// favor debuggability.
// TODO: Find a way to annotate the throw blocks as cold so they get laid out
// out-of-line.
BasicBlock *ThrowBlock =
BasicBlock::Create(*JitContext->LLVMContext, "ThrowNullRef", Function);
BasicBlock::Create(*JitContext->LLVMContext, ThrowBlockName, Function);
// Split the block. This creates a goto connecting the blocks that we'll
// replace with the conditional branch.
// Note that we split at offset NextInstrOffset rather than CurrInstrOffset.
// We're already generating the IR for the instr at CurrInstrOffset, and using
// NextInstrOffset here ensures that we won't redundantly try to add this
// instruction again when processing moves to the new NonNullBlock.
BasicBlock *NonNullBlock = ReaderBase::fgSplitBlock(
// instruction again when processing moves to the new ContinueBlock.
BasicBlock *ContinueBlock = ReaderBase::fgSplitBlock(
(FlowGraphNode *)CheckBlock, NextInstrOffset, (IRNode *)NextInstruction);
TerminatorInst *Goto = CheckBlock->getTerminator();
// Insert the compare against null.
LLVMBuilder->SetInsertPoint(Goto);
Value *Compare = LLVMBuilder->CreateIsNotNull(Node, "NullCheck");
// Swap the conditional branch in place of the goto.
LLVMBuilder->SetInsertPoint(Goto);
BranchInst *Branch =
LLVMBuilder->CreateCondBr(Compare, NonNullBlock, ThrowBlock);
LLVMBuilder->CreateCondBr(Condition, ThrowBlock, ContinueBlock);
Goto->eraseFromParent();
// FIll in the throw block.
LLVMBuilder->SetInsertPoint(ThrowBlock);
// TODO: Use throw_null_ref helper once that's available from CoreCLR. For
// now, use throw_div_zero since it has the right signature and we don't
// expect exceptions to work dynamically anyway.
CallInst *ThrowCall =
(CallInst *)callHelper(CORINFO_HELP_THROWDIVZERO, nullptr);
CallInst *ThrowCall = (CallInst *)callHelper(HelperId, nullptr);
ThrowCall->setDoesNotReturn();
LLVMBuilder->CreateUnreachable();
@ -3612,14 +3822,49 @@ IRNode *GenIR::genNullCheck(IRNode *Node) {
// Move the insert point back to the first instruction in the non-null path.
if (NextInstruction == nullptr) {
LLVMBuilder->SetInsertPoint(NonNullBlock);
LLVMBuilder->SetInsertPoint(ContinueBlock);
} else {
LLVMBuilder->SetInsertPoint(NonNullBlock->getFirstInsertionPt());
LLVMBuilder->SetInsertPoint(ContinueBlock->getFirstInsertionPt());
}
}
IRNode *GenIR::genNullCheck(IRNode *Node) {
// Insert the compare against null.
Value *Compare = LLVMBuilder->CreateIsNull(Node, "NullCheck");
// TODO: Use throw_null_ref helper once that's available from CoreCLR. For
// now, use throw_div_zero since it has the right signature and we don't
// expect exceptions to work dynamically anyway.
CorInfoHelpFunc HelperId = CORINFO_HELP_THROWDIVZERO;
genConditionalThrow(Compare, HelperId, "ThrowNullRef");
return Node;
};
// Generate array bounds check.
IRNode *GenIR::genBoundsCheck(IRNode *Array, IRNode *Index) {
CorInfoHelpFunc HelperId = CORINFO_HELP_RNGCHKFAIL;
// This call will load the array length which will ensure that the array is
// not null.
IRNode *ArrayLength = loadLen(Array);
// Insert the bound compare.
// The unsigned conversion allows us to also catch negative indices in the
// compare.
Type *ArrayLengthType = ArrayLength->getType();
ASSERTNR(Index->getType()->getPrimitiveSizeInBits() <=
ArrayLengthType->getPrimitiveSizeInBits());
bool IsSigned = false;
Value *ConvertedIndex =
LLVMBuilder->CreateIntCast(Index, ArrayLengthType, IsSigned);
Value *UpperBoundCompare =
LLVMBuilder->CreateICmpUGE(ConvertedIndex, ArrayLength, "BoundsCheck");
genConditionalThrow(UpperBoundCompare, HelperId, "ThrowIndexOutOfRange");
return Array;
};
void GenIR::leave(uint32_t TargetOffset, bool IsNonLocal,
bool EndsWithNonLocalGoto) {
// TODO: handle exiting through nested finallies
@ -3704,46 +3949,41 @@ IRNode *GenIR::makePtrNode(ReaderPtrType PtrType) { return loadNull(); }
IRNode *GenIR::derefAddress(IRNode *Address, bool DstIsGCPtr, bool IsConst,
bool AddressMayBeNull) {
// TODO: If IsConst is false, the load could cause a null pointer exception,
// so we may need an explicit null check. Not sure if there's a covering
// upstream check or not, so be cautious now.
if (!IsConst) {
throw NotYetImplementedException("non-const derefAddress");
}
// We don't know the true referent type so just use a pointer sized
// integer for the result.
Type *ReferentTy =
Type::getIntNTy(*JitContext->LLVMContext, TargetPointerSizeInBits);
// integer or GC pointer to i8 for the result.
Type *ReferentTy = DstIsGCPtr
? (Type *)getManagedPointerType(
Type::getInt8Ty(*JitContext->LLVMContext))
: (Type *)Type::getIntNTy(*JitContext->LLVMContext,
TargetPointerSizeInBits);
// Address is a pointer, but since it may come from dereferencing into
// runtime data structures with unknown field types, we may need a cast here
// to make it so.
Type *AddressTy = Address->getType();
if (!AddressTy->isPointerTy()) {
// Ensure we have a suitable integer value
ASSERT(AddressTy->isIntegerTy());
ASSERT(AddressTy->getScalarSizeInBits() == TargetPointerSizeInBits);
// We should not be trying to cast an integer value to a GC pointer.
ASSERT(!DstIsGCPtr);
// Cast to get a pointer-sized referent type.
PointerType *AddressPointerTy = dyn_cast<PointerType>(AddressTy);
if (AddressPointerTy == nullptr) {
// Cast the integer to an appropriate unmanaged pointer
Type *CastTy = getUnmanagedPointerType(ReferentTy);
Address = (IRNode *)LLVMBuilder->CreateIntToPtr(Address, CastTy);
} else if (DstIsGCPtr) {
// Verify we have a managed pointer.
ASSERT(isManagedPointerType(cast<PointerType>(AddressTy)));
// Cast to get a pointer-sized referent type.
Type *CastTy = getManagedPointerType(ReferentTy);
Address = (IRNode *)LLVMBuilder->CreatePointerCast(Address, CastTy);
} else {
// Verify we have an unmanaged pointer.
ASSERT(!isManagedPointerType(cast<PointerType>(AddressTy)));
// Cast to get a pointer-sized referent type.
Type *CastTy = getUnmanagedPointerType(ReferentTy);
} else if (AddressPointerTy->getElementType() != ReferentTy) {
// Cast to the appropriate referent type
Type *CastTy = isManagedPointerType(AddressPointerTy)
? getManagedPointerType(ReferentTy)
: getUnmanagedPointerType(ReferentTy);
Address = (IRNode *)LLVMBuilder->CreatePointerCast(Address, CastTy);
}
Value *Result = makeLoad(Address, false, AddressMayBeNull);
LoadInst *Result = makeLoad(Address, false, AddressMayBeNull);
if (IsConst) {
MDNode *EmptyNode =
MDNode::get(*JitContext->LLVMContext, ArrayRef<Metadata *>());
Result->setMetadata(LLVMContext::MD_invariant_load, EmptyNode);
}
return (IRNode *)Result;
}
@ -3752,14 +3992,14 @@ IRNode *GenIR::loadVirtFunc(IRNode *Arg1, CORINFO_RESOLVED_TOKEN *ResolvedToken,
IRNode *TypeToken = genericTokenToNode(ResolvedToken, true);
IRNode *MethodToken = genericTokenToNode(ResolvedToken);
Type *Ty = Type::getIntNTy(*this->JitContext->LLVMContext,
TargetPointerSizeInBits);
Type *Ty =
Type::getIntNTy(*this->JitContext->LLVMContext, TargetPointerSizeInBits);
IRNode *CodeAddress = callHelperImpl(CORINFO_HELP_VIRTUAL_FUNC_PTR, Ty, Arg1,
TypeToken, MethodToken);
FunctionType *FunctionType = getFunctionType(CallInfo->hMethod);
return (IRNode *)LLVMBuilder->CreateIntToPtr(CodeAddress,
getUnmanagedPointerType(FunctionType));
return (IRNode *)LLVMBuilder->CreateIntToPtr(
CodeAddress, getUnmanagedPointerType(FunctionType));
}
IRNode *GenIR::getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
ReaderAlignType Alignment, uint32_t *Align) {
@ -3780,8 +4020,8 @@ IRNode *GenIR::getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
if (!ReferentTy->isPointerTy()) {
// If we hit this we should fix the address producer, not
// coerce the type here.
throw
NotYetImplementedException("unexpected type in load/store primitive");
throw NotYetImplementedException(
"unexpected type in load/store primitive");
}
PointerType *ReferentPtrTy = cast<PointerType>(ReferentTy);
ASSERT(isManagedPointerType(ReferentPtrTy));
@ -3796,21 +4036,19 @@ IRNode *GenIR::getPrimitiveAddress(IRNode *Addr, CorInfoType CorInfoType,
Type *ReferentTy = PointerTy->getPointerElementType();
if (ReferentTy != ExpectedTy) {
Type *PtrToExpectedTy = isManagedPointerType(PointerTy)
? getManagedPointerType(ExpectedTy)
: getUnmanagedPointerType(ExpectedTy);
? getManagedPointerType(ExpectedTy)
: getUnmanagedPointerType(ExpectedTy);
TypedAddr =
(IRNode *)LLVMBuilder->CreatePointerCast(Addr, PtrToExpectedTy);
}
} else {
ASSERT(AddressTy->isIntegerTy());
Type *PtrToExpectedTy = getUnmanagedPointerType(ExpectedTy);
TypedAddr =
(IRNode *)LLVMBuilder->CreateIntToPtr(Addr, PtrToExpectedTy);
TypedAddr = (IRNode *)LLVMBuilder->CreateIntToPtr(Addr, PtrToExpectedTy);
}
}
*Align = (Alignment == Reader_AlignNatural) ? TargetPointerSizeInBits / 8
: Alignment;
*Align = convertReaderAlignment(Alignment);
return TypedAddr;
}
@ -4285,7 +4523,7 @@ void GenIR::maintainOperandStack(IRNode **Opr1, IRNode **Opr2,
Instruction *CurrentInst = SuccessorBlock->begin();
PHINode *Phi = nullptr;
for (IRNode* Current : *ReaderOperandStack) {
for (IRNode *Current : *ReaderOperandStack) {
Value *CurrentValue = (Value *)Current;
if (CreatePHIs) {
// The Successor has at least 2 predecessors so we use 2 as the

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше