зеркало из https://github.com/dotnet/llilc.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
Коммит
e695c16e6f
|
@ -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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче