@@ -93,8 +93,28 @@ PhaseStatus Compiler::fgExpandRuntimeLookups()
93
93
return fgExpandHelper<&Compiler::fgExpandRuntimeLookupsForCall>(false );
94
94
}
95
95
96
- bool Compiler::fgExpandRuntimeLookupsForCall (BasicBlock* block, Statement* stmt, GenTreeCall* call)
96
+ // ------------------------------------------------------------------------------
97
+ // fgExpandRuntimeLookupsForCall : partially expand runtime lookups helper calls
98
+ // to add a nullcheck [+ size check] and a fast path
99
+ //
100
+ // Arguments:
101
+ // pBlock - Block containing the helper call to expand. If expansion is performed,
102
+ // this is updated to the new block that was an outcome of block splitting.
103
+ // stmt - Statement containing the helper call
104
+ // call - The helper call
105
+ //
106
+ // Returns:
107
+ // true if a runtime lookup was found and expanded.
108
+ //
109
+ // Notes:
110
+ // The runtime lookup itself is needed to access a handle in code shared between
111
+ // generic instantiations. The lookup depends on the typeContext which is only available at
112
+ // runtime, and not at compile - time. See ASCII block diagrams in comments below for
113
+ // better understanding how this phase expands runtime lookups.
114
+ //
115
+ bool Compiler::fgExpandRuntimeLookupsForCall (BasicBlock** pBlock, Statement* stmt, GenTreeCall* call)
97
116
{
117
+ BasicBlock* block = *pBlock;
98
118
assert (call->IsHelperCall ());
99
119
100
120
if (!call->IsExpRuntimeLookup ())
@@ -150,6 +170,7 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock* block, Statement* stmt,
150
170
GenTree** callUse = nullptr ;
151
171
Statement* newFirstStmt = nullptr ;
152
172
block = fgSplitBlockBeforeTree (block, stmt, call, &newFirstStmt, &callUse);
173
+ *pBlock = block;
153
174
assert (prevBb != nullptr && block != nullptr );
154
175
155
176
// Block ops inserted by the split need to be morphed here since we are after morph.
@@ -433,9 +454,10 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess()
433
454
// that access fields marked with [ThreadLocal].
434
455
//
435
456
// Arguments:
436
- // block - Block containing the helper call to expand
437
- // stmt - Statement containing the helper call
438
- // call - The helper call
457
+ // pBlock - Block containing the helper call to expand. If expansion is performed,
458
+ // this is updated to the new block that was an outcome of block splitting.
459
+ // stmt - Statement containing the helper call
460
+ // call - The helper call
439
461
//
440
462
//
441
463
// Returns:
@@ -450,8 +472,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess()
450
472
// If the entry is not present, the helper is called, which would make an entry of current static block
451
473
// in the cache.
452
474
//
453
- bool Compiler::fgExpandThreadLocalAccessForCall (BasicBlock* block , Statement* stmt, GenTreeCall* call)
475
+ bool Compiler::fgExpandThreadLocalAccessForCall (BasicBlock** pBlock , Statement* stmt, GenTreeCall* call)
454
476
{
477
+ BasicBlock* block = *pBlock;
455
478
assert (call->IsHelperCall ());
456
479
if (!call->IsExpTLSFieldAccess ())
457
480
{
@@ -489,6 +512,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st
489
512
Statement* newFirstStmt = nullptr ;
490
513
DebugInfo debugInfo = stmt->GetDebugInfo ();
491
514
block = fgSplitBlockBeforeTree (block, stmt, call, &newFirstStmt, &callUse);
515
+ *pBlock = block;
492
516
assert (prevBb != nullptr && block != nullptr );
493
517
494
518
// Block ops inserted by the split need to be morphed here since we are after morph.
@@ -682,7 +706,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st
682
706
// Returns:
683
707
// true if there was any helper that was expanded.
684
708
//
685
- template <bool (Compiler::*ExpansionFunction)(BasicBlock*, Statement*, GenTreeCall*)>
709
+ template <bool (Compiler::*ExpansionFunction)(BasicBlock** , Statement*, GenTreeCall*)>
686
710
PhaseStatus Compiler::fgExpandHelper (bool skipRarelyRunBlocks)
687
711
{
688
712
PhaseStatus result = PhaseStatus::MODIFIED_NOTHING;
@@ -695,9 +719,14 @@ PhaseStatus Compiler::fgExpandHelper(bool skipRarelyRunBlocks)
695
719
}
696
720
697
721
// Expand and visit the last block again to find more candidates
698
- while (fgExpandHelperForBlock<ExpansionFunction>(block))
722
+ INDEBUG (BasicBlock* origBlock = block);
723
+ while (fgExpandHelperForBlock<ExpansionFunction>(&block))
699
724
{
700
725
result = PhaseStatus::MODIFIED_EVERYTHING;
726
+ #ifdef DEBUG
727
+ assert (origBlock != block);
728
+ origBlock = block;
729
+ #endif
701
730
}
702
731
}
703
732
@@ -715,16 +744,17 @@ PhaseStatus Compiler::fgExpandHelper(bool skipRarelyRunBlocks)
715
744
// invoke `fgExpand` if any of the tree node was a helper call.
716
745
//
717
746
// Arguments:
718
- // block - block to scan for static initializations
747
+ // pBlock - Block containing the helper call to expand. If expansion is performed,
748
+ // this is updated to the new block that was an outcome of block splitting.
719
749
// fgExpand - function that expands the helper call
720
750
//
721
751
// Returns:
722
752
// true if a helper was expanded
723
753
//
724
- template <bool (Compiler::*ExpansionFunction)(BasicBlock*, Statement*, GenTreeCall*)>
725
- bool Compiler::fgExpandHelperForBlock (BasicBlock* block )
754
+ template <bool (Compiler::*ExpansionFunction)(BasicBlock** , Statement*, GenTreeCall*)>
755
+ bool Compiler::fgExpandHelperForBlock (BasicBlock** pBlock )
726
756
{
727
- for (Statement* const stmt : block ->NonPhiStatements ())
757
+ for (Statement* const stmt : (*pBlock) ->NonPhiStatements ())
728
758
{
729
759
if ((stmt->GetRootNode ()->gtFlags & GTF_CALL) == 0 )
730
760
{
@@ -739,7 +769,7 @@ bool Compiler::fgExpandHelperForBlock(BasicBlock* block)
739
769
continue ;
740
770
}
741
771
742
- if ((this ->*ExpansionFunction)(block , stmt, tree->AsCall ()))
772
+ if ((this ->*ExpansionFunction)(pBlock , stmt, tree->AsCall ()))
743
773
{
744
774
return true ;
745
775
}
@@ -796,15 +826,17 @@ PhaseStatus Compiler::fgExpandStaticInit()
796
826
// Also, see fgExpandStaticInit's comments.
797
827
//
798
828
// Arguments:
799
- // block - call's block
800
- // stmt - call's statement
801
- // call - call that represents a static initialization
829
+ // pBlock - Block containing the helper call to expand. If expansion is performed,
830
+ // this is updated to the new block that was an outcome of block splitting.
831
+ // stmt - Statement containing the helper call
832
+ // call - The helper call
802
833
//
803
834
// Returns:
804
835
// true if a static initialization was expanded
805
836
//
806
- bool Compiler::fgExpandStaticInitForCall (BasicBlock* block , Statement* stmt, GenTreeCall* call)
837
+ bool Compiler::fgExpandStaticInitForCall (BasicBlock** pBlock , Statement* stmt, GenTreeCall* call)
807
838
{
839
+ BasicBlock* block = *pBlock;
808
840
assert (call->IsHelperCall ());
809
841
810
842
bool isGc = false ;
@@ -848,6 +880,7 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen
848
880
GenTree** callUse = nullptr ;
849
881
Statement* newFirstStmt = nullptr ;
850
882
block = fgSplitBlockBeforeTree (block, stmt, call, &newFirstStmt, &callUse);
883
+ *pBlock = block;
851
884
assert (prevBb != nullptr && block != nullptr );
852
885
853
886
// Block ops inserted by the split need to be morphed here since we are after morph.
0 commit comments