This commit is contained in:
rhadley 2015-03-31 12:58:37 -07:00
Родитель bd4250938d 129bd3f2a6
Коммит e03dc5fecf
7 изменённых файлов: 253 добавлений и 160 удалений

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

@ -81,16 +81,16 @@ public:
/// In addition, any cache coherency operations needed to reliably use the
/// memory are also performed.
///
/// \param ErrMsg[out] Additional information about finalization errors
/// \param ErrMsg [out] Additional information about finalization errors.
/// \returns false if an error occurred, true otherwise.
bool finalizeMemory(std::string *ErrMsg = nullptr) override;
/// Inform the memory manager about the total amount of memory required to
/// allocate all sections to be loaded.
///
/// \param CodeSize - the total size of all code sections
/// \param DataSizeRO - the total size of all read-only data sections
/// \param DataSizeRW - the total size of all read-write data sections
/// \param CodeSize - the total size of all code sections.
/// \param DataSizeRO - the total size of all read-only data sections.
/// \param DataSizeRW - the total size of all read-write data sections.
///
/// Note that by default the callback is disabled. To enable it
/// redefine the method needsToReserveAllocationSpace to return true.
@ -108,19 +108,19 @@ public:
///
/// This is currently invoked once per .xdata section. The EE uses this info
/// to build and register the appropriate .pdata with the OS.
/// \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
/// \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
/// \p LoadAddr are currently identical.
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override;
private:
LLILCJitContext *Context; ///< LLVM context for types, etc
uint8_t *HotCodeBlock; ///< Memory to hold the hot method code
uint8_t *ColdCodeBlock; ///< Memory to hold the cold method code
uint8_t *ReadOnlyDataBlock; ///< Memory to hold the readonly data
uint8_t *ReadOnlyDataUnallocated; ///< Address of unallocated part of RO data
LLILCJitContext *Context; ///< LLVM context for types, etc.
uint8_t *HotCodeBlock; ///< Memory to hold the hot method code.
uint8_t *ColdCodeBlock; ///< Memory to hold the cold method code.
uint8_t *ReadOnlyDataBlock; ///< Memory to hold the readonly data.
uint8_t *ReadOnlyDataUnallocated; ///< Address of unallocated part of RO data.
};
} // namespace llvm

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

@ -24,9 +24,9 @@
/// \brief Enum for LLVM IR Dump Level
enum LLVMDumpLevel {
NODUMP, ///< Do not dump any LLVM IR or summary
SUMMARY, ///< Only dump one line summary per method
VERBOSE ///< Dump full LLVM IR and method summary
NODUMP, ///< Do not dump any LLVM IR or summary.
SUMMARY, ///< Only dump one line summary per method.
VERBOSE ///< Dump full LLVM IR and method summary.
};
struct LLILCJitPerThreadState;
@ -43,7 +43,7 @@ struct LLILCJitPerThreadState;
struct LLILCJitContext {
/// Construct a context and push it onto the context stack.
/// \param State the per-thread state for this thread
/// \param State the per-thread state for this thread.
LLILCJitContext(LLILCJitPerThreadState *State);
/// Destruct this context and pop it from the context stack.
@ -73,32 +73,32 @@ struct LLILCJitContext {
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.
//@}
};
@ -114,8 +114,8 @@ struct LLILCJitPerThreadState {
public:
/// Construct a new state.
LLILCJitPerThreadState()
: LLVMContext(), ClassTypeMap(), ArrayTypeMap(), FieldIndexMap(),
JitContext(nullptr) {}
: LLVMContext(), ClassTypeMap(), BoxedTypeMap(), ArrayTypeMap(),
FieldIndexMap(), JitContext(nullptr) {}
/// Each thread maintains its own \p LLVMContext. This is where
/// LLVM keeps definitions of types and similar constructs.
@ -127,6 +127,10 @@ public:
/// Map from class handles to the LLVM types that represent them.
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> ClassTypeMap;
/// Map from class handles for value types to the LLVM types that represent
/// their boxed versions.
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> BoxedTypeMap;
/// \brief Map from class handles for arrays to the LLVM types that represent
/// them.
///
@ -165,11 +169,11 @@ public:
/// Main entry point into the jit. Invoked once per method to be jitted.
/// May be invoked re-entrantly and/or concurrently on multiple threads.
///
/// \param JitInfo Interface the jit can use for callbacks
/// \param MethodInfo Data structure describing the method to jit
/// \param Flags CorJitFlags controlling jit behavior
/// \param NativeEntry[out] Address of the jitted code
/// \param NativeSizeOfCode[out] Length of the jitted code
/// \param JitInfo Interface the jit can use for callbacks.
/// \param MethodInfo Data structure describing the method to jit.
/// \param Flags CorJitFlags controlling jit behavior.
/// \param NativeEntry [out] Address of the jitted code.
/// \param NativeSizeOfCode [out] Length of the jitted code.
///
/// \returns Code indicating success or failure of the jit request.
CorJitResult __stdcall compileMethod(ICorJitInfo *JitInfo,
@ -181,7 +185,7 @@ public:
void clearCache() override;
/// Check if cache cleanup is required.
/// \returns \p true if the jit is caching information
/// \returns \p true if the jit is caching information.
BOOL isCacheCleanupRequired() override;
/// \brief Get the Jit's version identifier.
@ -190,17 +194,21 @@ public:
/// the jit for a version identifier GUID, and verify that it matches the
/// expectations of the EE.
///
/// \param VersionIdentifier[out] Buffer where the jit's GUID can be stored
/// \param VersionIdentifier [out] Buffer where the jit's GUID can be stored.
void getVersionIdentifier(GUID *VersionIdentifier) override;
/// \brief Get access to the current jit context.
///
/// This method can be called from anywhere to retrieve the current jit
/// context.
///
/// \returns Context for the current jit request.
static LLILCJitContext *getLLILCJitContext() {
return TheJit->State.get()->JitContext;
}
/// Report a fatal error in the Jit.
/// \param Errnum Error number to report in exception context
/// \param Errnum Error number to report in exception context.
static void __cdecl fatal(int Errnum, ...);
/// Signal handler for LLVM abort signals.

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

@ -1220,10 +1220,10 @@ public:
/// direct client processing for the method parameters and the local
/// variables of the method.
///
/// \param NumParams Number of parameters to the method. Note this
/// \param NumParam Number of parameters to the method. Note this
/// includes implicit parameters like the this
/// pointer.
/// \param NumAutos Number of locals described in the local
/// \param NumAuto Number of locals described in the local
/// signature.
/// \param HasSecretParameter Indicates whether or not the terminal parameter
/// is the secret parameter of an IL stub.
@ -1269,7 +1269,7 @@ public:
CORINFO_CLASS_HANDLE *Class = nullptr,
bool *IsPinned = nullptr);
/// \brief Build the flow graph for the method
/// \brief Build the flow graph for the method.
///
/// Create a flow graph for the method. This determines which range of
/// MSIL instructions will lie within each node in the flow graph,
@ -1279,7 +1279,7 @@ public:
/// \returns The first flow graph node in the graph.
FlowGraphNode *buildFlowGraph(FlowGraphNode **FgTail);
/// \brief Split a flow graph node (aka block)
/// \brief Split a flow graph node (aka block).
///
/// Break the indicated \p Block into two blocks, with the divsion
/// happening at the indicated MSIL \p Offset. The client method
@ -1289,7 +1289,7 @@ public:
/// \param Block The flow graph mode to split
/// \param Offset The MSIL offset of the split point. Must be within
/// the MSIL range for the block.
/// \param IRNode The IR node corresponding to the split point.
/// \param Node The IR node corresponding to the split point.
/// \returns The new node.
FlowGraphNode *fgSplitBlock(FlowGraphNode *Block, uint32_t Offset,
IRNode *Node);
@ -1300,69 +1300,69 @@ public:
/// Print the MSIL in the buffer for the given range. Output emitted via
/// \p dbPrint().
///
/// \param Buf Buffer containing MSIL bytecode
/// \param StartOffset Initial offset for the range to print
/// \param EndOffset Ending offset for the range to print
/// \param Buf Buffer containing MSIL bytecode.
/// \param StartOffset Initial offset for the range to print.
/// \param EndOffset Ending offset for the range to print.
void printMSIL(uint8_t *Buf, uint32_t StartOffset, uint32_t EndOffset);
#endif
/// \brief Determine the effect of this instruction on the operand stack
/// \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
/// pops for a particular instruction.
///
/// \param Opcode The MSIL opcode for the instruction
/// \param Opcode The MSIL opcode for the instruction.
/// \param Operand For call opcodes with signature tokens, pointer to the
/// token value in the IL stream
/// \param Pop [out] Number of operands popped from the stack
/// \param Push [out] Number of operands pushed onto the stack
/// token value in the IL stream.
/// \param Pop [out] Number of operands popped from the stack.
/// \param Push [out] Number of operands pushed onto the stack.
void getMSILInstrStackDelta(ReaderBaseNS::OPCODE Opcode, uint8_t *Operand,
uint16_t *Pop, uint16_t *Push);
private:
/// \brief Determine if a call instruction is a candidate to be a tail call
/// \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 tail prefix. This method determines if such treatment is possible.
///
/// \param ILInput Pointer to the start of the MSIL bytecode stream
/// \param ILInputSize Length of the MSIL bytecode stream
/// \param NextOffset Offset into the stream just past the call
/// \param Token Token value for calls that have sig tokens
/// \param ILInput Pointer to the start of the MSIL bytecode stream.
/// \param ILInputSize Length of the MSIL bytecode stream.
/// \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
/// reasonble.
bool isUnmarkedTailCall(uint8_t *ILInput, uint32_t ILInputSize,
uint32_t NextOffset, mdToken Token);
/// \brief Helper method called from \p isUnmarkedTailCall
/// \brief Helper method called from \p isUnmarkedTailCall.
///
/// \param ILInput Pointer to the start of the MSIL bytecode stream
/// \param ILInputSize Length of the MSIL bytecode stream
/// \param NextOffset Offset into the stream just past the call
/// \param Token Token value for calls that have sig tokens
/// \param ILInput Pointer to the start of the MSIL bytecode stream.
/// \param ILInputSize Length of the MSIL bytecode stream.
/// \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
/// 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
/// \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
/// followed by a single pop before reaching the
/// \param ILOffset Offset of the call instruction in the IL stream.
/// \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
/// tail call.
bool checkExplicitTailCall(uint32_t ILOffset, bool AllowPop);
/// \brief Convert the MSIL for this flow graph node into the client IR
/// \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
@ -1373,18 +1373,17 @@ private:
/// \param IsVerifyOnly True if the reader is only verifying the MSIL.
void readBytesForFlowGraphNode(FlowGraphNode *Fg, bool IsVerifyOnly);
/// \brief Helper method for \p readBytesForFlowGraphNode
/// \brief Helper method for \p readBytesForFlowGraphNode.
///
/// 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
/// \param IsVerifyOnly True if the reader is only verifying the MSIL.
/// \param Param Encapsulated state from the main method.
void
readBytesForFlowGraphNodeHelper(ReadBytesForFlowGraphNodeHelperParam *Param);
protected:
/// \brief Create or return a flow graph node for the indicated offset
/// \brief Create or return a flow graph node for the indicated offset.
///
/// 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
@ -1392,25 +1391,25 @@ protected:
/// 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
/// \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.
FlowGraphNodeOffsetList *fgAddNodeMSILOffset(FlowGraphNode **Node,
uint32_t TargetOffset);
/// Get the innermost finally region enclosing the given \p Offset
/// Get the innermost finally region enclosing the given \p Offset.
///
/// \param Offset MSIL offset of interest
/// \param Offset MSIL offset of interest.
/// \returns The innermost finally region enclosing \p Offset if one exists;
/// nullptr otherwise
/// nullptr otherwise.
EHRegion *getInnermostFinallyRegion(uint32_t Offset);
/// Find the next-innermost region enclosing the given \p Offset
/// Find the next-innermost region enclosing the given \p Offset.
///
/// \param OuterRegion Limit search to regions nested inside OuterRegion
/// \param Offset Limit search to regions enclosing Offset
/// \param OuterRegion Limit search to regions nested inside OuterRegion.
/// \param Offset Limit search to regions enclosing Offset.
/// \returns The outermost region that is nested inside \p OuterRegion and
/// that includes \p Offset, if such a region exists; else nullptr
/// that includes \p Offset, if such a region exists; else nullptr.
EHRegion *getInnerEnclosingRegion(EHRegion *OuterRegion, uint32_t Offset);
private:
@ -1426,11 +1425,11 @@ private:
/// Helper used to check whether branch targets and similar are referring
/// to the start of instructions.
///
/// \param Offset Offset into the MSIL stream
/// \returns True if \pO Offset is the start of an MSIL instruction.
/// \param Offset Offset into the MSIL stream.
/// \returns True if \p Offset is the start of an MSIL instruction.
bool isOffsetInstrStart(uint32_t Offset);
// \brief Get custom sequence points
// \brief Get custom sequence points.
///
/// This method checks with the EE to see if there are any debugger-specified
/// sequence points in the method. The results of this call is a bit vector
@ -1448,30 +1447,30 @@ private:
/// instructions (branches and similar). Uses these to instruct the client
/// to produce a flow graph describing the method's control flow.
///
/// \param Buffer Buffer of MSIL bytecodes
/// \param BufferSize Length of the buffer in bytes
/// \param Buffer Buffer of MSIL bytecodes.
/// \param BufferSize Length of the buffer in bytes.
/// \returns Head node of the flow graph.
FlowGraphNode *fgBuildBasicBlocksFromBytes(uint8_t *Buffer,
uint32_t BufferSize);
/// \brief First pass of flow graph construction
/// \brief First pass of flow graph construction.
///
/// 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
/// 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
/// \param Fg Nominal entry node for the method.
/// \param Buffer Buffer of MSIL bytecodes.
/// \param BufferSize Length of the buffer in bytes.
void fgBuildPhase1(FlowGraphNode *Fg, uint8_t *Buffer, uint32_t BufferSize);
/// Create initial global verification data for all blocks in the flow graph
/// Create initial global verification data for all blocks in the flow graph.
///
/// \param HeadBlock Initial block in the flow graph
/// \param HeadBlock Initial block in the flow graph.
void fgAttachGlobalVerifyData(FlowGraphNode *HeadBlock);
/// Perform special case repair for recursive tail call and localloc
/// Perform special case repair for recursive tail call and localloc.
///
/// The flow graph builder can optimistically describe recursive tail
/// calls as branches back to the start of the method. However this must
@ -1482,22 +1481,22 @@ private:
/// Helper method for building up the cases of a switch.
///
/// \param SwitchNode The client IR representing the switch
/// \param LabelNode The client IR representing the case target
/// \param Element The switch value for this case
/// \param SwitchNode The client IR representing the switch.
/// \param LabelNode The client IR representing the case target.
/// \param Element The switch value for this case.
/// \returns The case node added to the switch.
IRNode *fgAddCaseToCaseListHelper(IRNode *SwitchNode, IRNode *LabelNode,
uint32_t Element);
/// \brief Add the unvisited successors of this block to the worklist
/// \brief Add the unvisited successors of this block to the worklist.
///
/// 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,
/// returning a new worklist head node.
///
/// \param Worklist The current worklist of unvisited blocks
/// \param CurrBlock The block to examine for unvisited successors
/// \param Worklist The current worklist of unvisited blocks.
/// \param CurrBlock The block to examine for unvisited successors.
/// \returns Updated list of unvisited blocks.
FlowGraphNodeWorkList *
fgAppendUnvisitedSuccToWorklist(FlowGraphNodeWorkList *Worklist,
@ -1527,8 +1526,8 @@ private:
/// Scan the EH regions of the method looking for the smallest region
/// that contains this MSIL offset.
///
/// \param Offset The MSIL offset in question
/// \returns Pointer to the innermost region, or nullptr if none
/// \param Offset The MSIL offset in question.
/// \returns Pointer to the innermost region, or nullptr if none.
EHRegion *fgGetRegionFromMSILOffset(uint32_t Offset);
/// \brief Update the branches with temporary targets at this offset.
@ -1538,84 +1537,84 @@ private:
/// a particular temporary node with the actual node representing the
/// target in the flow graph.
///
/// \param Offset The MSIL offset of the branch target
/// \param TempBranchTarget The placeholder node for the target
/// \param Offset The MSIL offset of the branch target.
/// \param TempBranchTarget The placeholder node for the target.
/// \param StartBlock A node at an offset less than the target.
/// \returns The updated target block
/// \returns The updated target block.
FlowGraphNode *fgReplaceBranchTarget(uint32_t Offset,
FlowGraphNode *TempBranchTarget,
FlowGraphNode *StartBlock);
/// \brief Update all branches with temporary targets
/// \brief Update all branches with temporary targets.
///
/// 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();
/// Process the end of a try region
/// \param EHRegion The region to process.
/// Process the end of a try region.
/// \param EhRegion The region to process.
void fgInsertTryEnd(EHRegion *EhRegion);
/// Place client IR into the start of the EH region that begins at Offset.
///
/// \param Offset MSIL offset of the start of an EH region
/// \param EHNode Client IR to insert into the block that
/// \param Offset MSIL offset of the start of an EH region.
/// \param EHNode Client IR to insert into the block that.
/// starts that region.
void fgInsertBeginRegionExceptionNode(uint32_t Offset, IRNode *EHNode);
/// Place client IR into the end of the EH region that ends at Offset.
///
/// \param Offset MSIL offset of the end of an EH region
/// \param Offset MSIL offset of the end of an EH region.
/// \param EHNode Client IR to insert into the block that
/// ends that region.
void fgInsertEndRegionExceptionNode(uint32_t Offset, IRNode *EHNode);
/// Add client IR for an EH region and all contained regions.
///
/// \param Region Root region to process
/// \param Region Root region to process.
void fgInsertEHAnnotations(EHRegion *Region);
/// \brief Create branch IR
/// \brief Create branch IR.
///
/// Have the client create a branch to \p LabelNode from \p BlockNode.
///
/// \param LabelNode target block of the branch
/// \param BlockNode source block for the branch
/// \param Offset MSIL offset of the branch target
/// \param IsConditional true if this is a conditional branch
/// \param IsNominal true if this is a nominal branch
/// \returns IRNode for the branch created
/// \param LabelNode target block of the branch.
/// \param BlockNode source block for the branch.
/// \param Offset MSIL offset of the branch target.
/// \param IsConditional true if this is a conditional branch.
/// \param IsNominal true if this is a nominal branch.
/// \returns IRNode for the branch created.
IRNode *fgMakeBranchHelper(IRNode *LabelNode, IRNode *BlockNode,
uint32_t Offset, bool IsConditional,
bool IsNominal);
/// \brief Create IR for an endfinally instruction
/// \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.
///
/// \param BlockNode the block that is the end of the finally
/// \param FinallyRegion the finally region being ended
/// \param Offset msil offset for the endfinally instruction
/// \returns the branch generated to terminate the block for this endfinally
/// \param BlockNode the block that is the end of the finally.
/// \param FinallyRegion the finally region being ended.
/// \param Offset msil offset for the endfinally instruction.
/// \returns the branch generated to terminate the block for this endfinally.
IRNode *fgMakeEndFinallyHelper(IRNode *BlockNode, EHRegion *FinallyRegion,
uint32_t Offset);
/// \brief Remove all unreachable blocks
/// \brief Remove all unreachable blocks.
///
/// Walk the flow graph and remove any block (except the tail block)
/// that cannot be reached from the head block. Blocks are removed by
/// calling \p fgDeleteBlockAndNodes.
///
/// \param FgHead the head block of the flow graph
/// \param FgTail the tail block of the flow graph
/// \param FgHead the head block of the flow graph.
/// \param FgTail the tail block of the flow graph.
void fgRemoveUnusedBlocks(FlowGraphNode *FgHead, FlowGraphNode *FgTail);
/// Find the canonical landing point for leaves from an EH region
/// Find the canonical landing point for leaves from an EH region.
///
/// \param Region The region in question.
/// \returns The MSIL offset of the canonical landing point
/// \returns The MSIL offset of the canonical landing point.
uint32_t fgGetRegionCanonicalExitOffset(EHRegion *Region);
/// Buffer used by \p fgGetRegionCanonicalExitOffset for cases where
@ -1624,13 +1623,13 @@ private:
/// Determine if a leave exits the enclosing EH region in a non-local manner.
///
/// \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
/// canonical exit offset of the region
/// \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
/// canonical exit offset of the region.
///
/// \returns True if this is a nonlocal leave
/// \returns True if this is a nonlocal leave.
bool fgLeaveIsNonLocal(FlowGraphNode *Fg, uint32_t LeaveOffset,
uint32_t LeaveTarget, bool *EndsWithNonLocalGoto);

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

@ -267,7 +267,7 @@ enum ConvOpcode {
ConvOvfI4, ///< As #ConvI4, but throws an exception if the result is out of
///< range.
ConvOnvI8, ///< As #ConvI8, but throws an exception if the result is out of
ConvOvfI8, ///< As #ConvI8, but throws an exception if the result is out of
///< range.
ConvOvfU1, ///< As #ConvU1, but throws an exception if the result is out of
@ -306,7 +306,7 @@ enum ConvOpcode {
ConvOvfIUn, ///< As #ConvOvfI, but treats its input as an unsigned integer.
ConvOvfUUn, ///< As #ConvOvfIU, but treats its input as an unsigned integer.
ConvOvfUUn, ///< As #ConvOvfU, but treats its input as an unsigned integer.
ConvRUn, ///< Converts its argument to a floating-point number in the
///< runtime's internal representation, treating its input as an
@ -711,7 +711,7 @@ SELECTANY const char OpcodeRemap[ReaderBaseNS::CEE_MACRO_END -
ReaderBaseNS::ConvOvfU2, // CEE_CONV_OVF_U2,
ReaderBaseNS::ConvOvfI4, // CEE_CONV_OVF_I4,
ReaderBaseNS::ConvOvfU4, // CEE_CONV_OVF_U4,
ReaderBaseNS::ConvOnvI8, // CEE_CONV_OVF_I8,
ReaderBaseNS::ConvOvfI8, // CEE_CONV_OVF_I8,
ReaderBaseNS::ConvOvfU8, // CEE_CONV_OVF_U8,
-1, // CEE_UNUSED50,
-1, // CEE_UNUSED18,

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

@ -240,6 +240,7 @@ class GenIR : public ReaderBase {
public:
GenIR(LLILCJitContext *JitContext,
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *ClassTypeMap,
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *BoxedTypeMap,
std::map<std::tuple<CorInfoType, CORINFO_CLASS_HANDLE, uint32_t>,
llvm::Type *> *ArrayTypeMap,
std::map<CORINFO_FIELD_HANDLE, uint32_t> *FieldIndexMap)
@ -247,6 +248,7 @@ public:
JitContext->Flags) {
this->JitContext = JitContext;
this->ClassTypeMap = ClassTypeMap;
this->BoxedTypeMap = BoxedTypeMap;
this->ArrayTypeMap = ArrayTypeMap;
this->FieldIndexMap = FieldIndexMap;
}
@ -847,6 +849,13 @@ private:
llvm::Type *getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
bool GetRefClassFields);
/// \brief Construct the LLVM type of the boxed representation of the given
/// value type.
///
/// \param Class The handle to the value type's class.
/// \returns The LLVM type of the boxed representation of the value type.
llvm::Type *getBoxedType(CORINFO_CLASS_HANDLE Class);
/// Convert node to the desired type.
/// May reinterpret, truncate, or extend as needed.
/// \param Type Desired type
@ -1168,6 +1177,7 @@ private:
// insertion point parameters).
llvm::IRBuilder<> *LLVMBuilder;
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *ClassTypeMap;
std::map<CORINFO_CLASS_HANDLE, llvm::Type *> *BoxedTypeMap;
std::map<std::tuple<CorInfoType, CORINFO_CLASS_HANDLE, uint32_t>,
llvm::Type *> *ArrayTypeMap;
std::map<CORINFO_FIELD_HANDLE, uint32_t> *FieldIndexMap;

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

@ -285,7 +285,8 @@ bool LLILCJit::readMethod(LLILCJitContext *JitContext) {
LLILCJitPerThreadState *PerThreadState = State.get();
GenIR Reader(JitContext, &PerThreadState->ClassTypeMap,
&PerThreadState->ArrayTypeMap, &PerThreadState->FieldIndexMap);
&PerThreadState->BoxedTypeMap, &PerThreadState->ArrayTypeMap,
&PerThreadState->FieldIndexMap);
std::string FuncName = JitContext->CurrentModule->getModuleIdentifier();

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

@ -269,18 +269,21 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
ASSERTNR(UNREACHED);
}
const uint32_t JitFlags = JitContext->Flags;
HasSecretParameter = (JitFlags & CORJIT_FLG_PUBLISH_SECRET_PARAM) != 0;
CORINFO_METHOD_HANDLE MethodHandle = JitContext->MethodInfo->ftn;
Function = getFunction(MethodHandle, HasSecretParameter);
// Capture low-level info about the return type for use in Return.
CORINFO_SIG_INFO Sig;
getMethodSig(MethodHandle, &Sig);
ReturnCorType = Sig.retType;
if ((ReturnCorType == CORINFO_TYPE_REFANY) ||
(ReturnCorType == CORINFO_TYPE_VALUECLASS)) {
throw NotYetImplementedException("Return refany or value class");
}
const uint32_t JitFlags = JitContext->Flags;
HasSecretParameter = (JitFlags & CORJIT_FLG_PUBLISH_SECRET_PARAM) != 0;
Function = getFunction(MethodHandle, HasSecretParameter);
EntryBlock = BasicBlock::Create(*JitContext->LLVMContext, "entry", Function);
LLVMBuilder = new IRBuilder<>(*this->JitContext->LLVMContext);
@ -1329,6 +1332,72 @@ Type *GenIR::getClassType(CORINFO_CLASS_HANDLE ClassHandle, bool IsRefClass,
return ResultTy;
}
Type *GenIR::getBoxedType(CORINFO_CLASS_HANDLE Class) {
assert(JitContext->JitInfo->isValueClass(Class));
// Check to see if the boxed version of this type has already been generated.
auto MapElement = BoxedTypeMap->find(Class);
if (MapElement != BoxedTypeMap->end()) {
return MapElement->second;
}
// Normalize the source type from Nullable<T> to T, if necessary.
CORINFO_CLASS_HANDLE TypeToBox = getTypeForBox(Class);
CorInfoType CorType = ReaderBase::getClassType(TypeToBox);
Type *ValueType = getType(CorType, TypeToBox);
// Treat the boxed type as a subclass of Object with a single field of the
// source type.
CORINFO_CLASS_HANDLE ObjectClass =
getBuiltinClass(CorInfoClassId::CLASSID_SYSTEM_OBJECT);
const bool IsRefClass = true;
const bool GetRefClassFields = true;
Type *ObjectPtrType =
getClassType(ObjectClass, IsRefClass, GetRefClassFields);
StructType *ObjectType =
cast<StructType>(ObjectPtrType->getPointerElementType());
ArrayRef<Type *> ObjectFields = ObjectType->elements();
std::vector<Type *> Fields(ObjectFields.size() + 1);
int I = 0;
for (auto F : ObjectFields) {
Fields[I++] = F;
}
Fields[I] = ValueType;
LLVMContext &Context = *JitContext->LLVMContext;
const bool IsPacked = true;
Type *BoxedType;
std::string BoxedTypeName;
StructType *TheStructType = dyn_cast<StructType>(ValueType);
if (TheStructType != nullptr) {
StringRef StructTypeName = TheStructType->getStructName();
if (!StructTypeName.empty()) {
BoxedTypeName = Twine("Boxed_", StructTypeName).str();
} else {
BoxedTypeName = "Boxed_AnonStruct";
}
}
if (BoxedTypeName.empty()) {
assert(ValueType->isFloatTy() || ValueType->isDoubleTy() ||
ValueType->isIntegerTy());
BoxedTypeName = "Boxed_Primitive";
}
BoxedType = StructType::create(Context, Fields, BoxedTypeName, IsPacked);
BoxedType = getManagedPointerType(BoxedType);
(*BoxedTypeMap)[TypeToBox] = BoxedType;
if (Class != TypeToBox) {
(*BoxedTypeMap)[Class] = BoxedType;
}
return BoxedType;
}
// Obtain an LLVM function type from a method handle.
FunctionType *GenIR::getFunctionType(CORINFO_METHOD_HANDLE Method,
bool HasSecretParameter) {
@ -2324,8 +2393,11 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1,
Instruction::BinaryOps Op = Triple[Opcode].Op.Opcode;
if ((Op == Instruction::BinaryOps::SDiv) ||
(Op == Instruction::BinaryOps::UDiv)) {
// Integer divide throws a DivideByZeroException on 0 denominator
(Op == Instruction::BinaryOps::UDiv) ||
(Op == Instruction::BinaryOps::SRem) ||
(Op == Instruction::BinaryOps::URem)) {
// Integer divide and remainder throw a DivideByZeroException
// if the divisor is zero
if (UseExplicitZeroDivideChecks) {
Value *IsZero = LLVMBuilder->CreateIsNull(Arg2);
genConditionalThrow(IsZero, CORINFO_HELP_THROWDIVZERO,
@ -2686,8 +2758,9 @@ IRNode *GenIR::loadAtAddress(IRNode *Address, Type *Ty, CorInfoType CorType,
ReaderAlignType AlignmentPrefix, bool IsVolatile,
bool AddressMayBeNull) {
if (Ty->isStructTy()) {
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile, true,
AddressMayBeNull);
bool IsFieldAccess = ResolvedToken->hField != nullptr;
return loadObj(ResolvedToken, Address, AlignmentPrefix, IsVolatile,
IsFieldAccess, AddressMayBeNull);
} else {
LoadInst *LoadInst = makeLoad(Address, IsVolatile, AddressMayBeNull);
uint32_t Align = convertReaderAlignment(AlignmentPrefix);
@ -2944,9 +3017,7 @@ IRNode *GenIR::addressOfValue(IRNode *Leaf) {
}
IRNode *GenIR::makeBoxDstOperand(CORINFO_CLASS_HANDLE Class) {
const bool IsRefClass = false;
const bool GetRefClassFields = false;
Type *Ty = getClassType(getTypeForBox(Class), IsRefClass, GetRefClassFields);
Type *Ty = getBoxedType(Class);
Value *Ptr = llvm::Constant::getNullValue(getManagedPointerType(Ty));
return (IRNode *)Ptr;
}
@ -4715,7 +4786,7 @@ IRNode *GenIR::conditionalDerefAddress(IRNode *Address) {
// Merge the two addresses and return the result.
PHINode *Result = mergeConditionalResults(ContinueBlock, Address, TestBlock,
UpdatedAddress, ContinueBlock);
UpdatedAddress, IndirectionBlock);
return (IRNode *)Result;
}
@ -5163,16 +5234,20 @@ IRNode *GenIR::castOp(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ObjRefNode,
}
}
Type *ResultType =
getType(CorInfoType::CORINFO_TYPE_CLASS, ResolvedToken->hClass);
IRNode *Dst = (IRNode *)Constant::getNullValue(ResultType);
CORINFO_CLASS_HANDLE Class = ResolvedToken->hClass;
Type *ResultType = nullptr;
if (JitContext->JitInfo->isValueClass(Class)) {
ResultType = getBoxedType(Class);
} else {
ResultType = getType(CORINFO_TYPE_CLASS, Class);
}
// Generate the helper call or intrinsic
bool IsVolatile = false;
bool DoesNotInvokeStaticCtor = Optimize;
return callHelper(HelperId, Dst, ClassHandleNode, ObjRefNode, nullptr,
nullptr, Reader_AlignUnknown, IsVolatile,
DoesNotInvokeStaticCtor);
const bool IsVolatile = false;
const bool DoesNotInvokeStaticCtor = Optimize;
return callHelperImpl(HelperId, ResultType, ClassHandleNode, ObjRefNode,
nullptr, nullptr, Reader_AlignUnknown, IsVolatile,
DoesNotInvokeStaticCtor);
}
// Override the cast class optimization