Skip to content

Commit

Permalink
Improvements for object stack allocation.
Browse files Browse the repository at this point in the history
This change enables object stack allocation for more cases.

1. Objects with gc fields can now be stack-allocated.
2. Object stack allocation is enabled for x86.

ObjectAllocator updates the types of trees containing references
to possibly-stack-allocated objects to TYP_BYREF or TYP_I_IMPL as appropriate.
That allows us to remove the hacks in gcencode.cpp and refine reporting of pointers:
the pointer is not reported when we can prove that it always points to a stack-allocated object or is null (typed as TYP_I_IMPL);
the pointer is reported as an interior pointer when it may point to either a stack-allocated object or a heap-allocated object (typed as TYP_BYREF);
the pointer is reported as a normal pointer when it points to a heap-allocated object (typed as TYP_REF).

ObjectAllocator also adds flags to indirections:
GTF_IND_TGTANYWHERE when the indirection may be the heap or the stack
(that results in checked write barriers used for writes)
or the new GTF_IND_TGT_NOT_HEAP when the indirection is null or stack memory
(that results in no barrier used for writes).


Commit migrated from dotnet/coreclr@f2d3dfe
  • Loading branch information
erozenfeld committed Jan 15, 2019
1 parent 852c286 commit d135221
Show file tree
Hide file tree
Showing 11 changed files with 400 additions and 97 deletions.
4 changes: 4 additions & 0 deletions src/coreclr/src/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9269,6 +9269,10 @@ int cTreeFlagsIR(Compiler* comp, GenTree* tree)
{
chars += printf("[IND_TGTANYWHERE]");
}
if (tree->gtFlags & GTF_IND_TGT_NOT_HEAP)
{
chars += printf("[IND_TGT_NOT_HEAP]");
}
if (tree->gtFlags & GTF_IND_TLS_REF)
{
chars += printf("[IND_TLS_REF]");
Expand Down
28 changes: 0 additions & 28 deletions src/coreclr/src/jit/gcencode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4245,7 +4245,6 @@ void GCInfo::gcMakeRegPtrTable(
// Or in byref_OFFSET_FLAG for 'byref' pointer tracking
flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
}
gcUpdateFlagForStackAllocatedObjects(flags);

if (varDsc->lvPinned)
{
Expand Down Expand Up @@ -4345,7 +4344,6 @@ void GCInfo::gcMakeRegPtrTable(
{
flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
}
gcUpdateFlagForStackAllocatedObjects(flags);

GcStackSlotBase stackSlotBase = GC_SP_REL;
if (compiler->isFramePointerUsed())
Expand Down Expand Up @@ -4730,7 +4728,6 @@ void GCInfo::gcInfoRecordGCRegStateChange(GcInfoEncoder* gcInfoEncoder,
{
regFlags = (GcSlotFlags)(regFlags | GC_SLOT_INTERIOR);
}
gcUpdateFlagForStackAllocatedObjects(regFlags);

RegSlotIdKey rskey(regNum, regFlags);
GcSlotId regSlotId;
Expand Down Expand Up @@ -4821,7 +4818,6 @@ void GCInfo::gcMakeVarPtrTable(GcInfoEncoder* gcInfoEncoder, MakeRegPtrMode mode
{
flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
}
gcUpdateFlagForStackAllocatedObjects(flags);

if ((lowBits & pinned_OFFSET_FLAG) != 0)
{
Expand Down Expand Up @@ -4925,30 +4921,6 @@ void GCInfo::gcInfoRecordGCStackArgsDead(GcInfoEncoder* gcInfoEncoder,
}
}

//------------------------------------------------------------------------
// gcUpdateFlagForStackAllocatedObjects: Update the flags to handle a possibly stack-allocated object.
// allocation.
// Arguments:
// flags - flags to update
//
//
// Notes:
// TODO-ObjectStackAllocation: This is a temporary conservative implementation.
// Currently variables pointing to heap and/or stack allocated objects have type TYP_REF so we
// conservatively report them as INTERIOR.
// Ideally we should have the following types for object pointers:
// 1. TYP_I_IMPL for variables always pointing to stack-allocated objects (not reporting to GC)
// 2. TYP_REF for variables always pointing to heap-allocated objects (reporting as normal objects to GC)
// 3. TYP_BYREF for variables that may point to the stack or to the heap (reporting as interior objects to GC)

void GCInfo::gcUpdateFlagForStackAllocatedObjects(GcSlotFlags& flags)
{
if ((compiler->optMethodFlags & OMF_HAS_OBJSTACKALLOC) != 0)
{
flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
}
}

#undef GCENCODER_WITH_LOGGING

#endif // !JIT32_GCENCODER
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/src/jit/gcinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ GCInfo::WriteBarrierForm GCInfo::gcIsWriteBarrierCandidate(GenTree* tgt, GenTree
// This case occurs for Span<T>.
return WBF_NoBarrier;
}
if (tgt->gtFlags & GTF_IND_TGT_NOT_HEAP)
{
// This indirection is not from to the heap.
// This case occurs for stack-allocated objects.
return WBF_NoBarrier;
}
return gcWriteBarrierFormFromTargetAddress(tgt->gtOp.gtOp1);

case GT_LEA:
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/src/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9337,6 +9337,12 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z _
--msgLength;
break;
}
if (tree->gtFlags & GTF_IND_TGT_NOT_HEAP)
{
printf("s");
--msgLength;
break;
}
if (tree->gtFlags & GTF_IND_INVARIANT)
{
printf("#");
Expand Down Expand Up @@ -14439,6 +14445,11 @@ GenTree* Compiler::gtNewTempAssign(
{
ok = true;
}
// 3) TYP_BYREF = TYP_REF when object stack allocation is enabled
else if (JitConfig.JitObjectStackAllocation() && (dstTyp == TYP_BYREF) && (valTyp == TYP_REF))
{
ok = true;
}

if (!ok)
{
Expand Down
10 changes: 7 additions & 3 deletions src/coreclr/src/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ struct GenTree
#define GTF_INX_REFARR_LAYOUT 0x20000000 // GT_INDEX
#define GTF_INX_STRING_LAYOUT 0x40000000 // GT_INDEX -- this uses the special string array layout

#define GTF_IND_TGT_NOT_HEAP 0x80000000 // GT_IND -- the target is not on the heap
#define GTF_IND_VOLATILE 0x40000000 // GT_IND -- the load or store must use volatile sematics (this is a nop on X86)
#define GTF_IND_NONFAULTING 0x20000000 // Operations for which OperIsIndir() is true -- An indir that cannot fault.
// Same as GTF_ARRLEN_NONFAULTING.
Expand All @@ -818,7 +819,7 @@ struct GenTree

#define GTF_IND_FLAGS \
(GTF_IND_VOLATILE | GTF_IND_TGTANYWHERE | GTF_IND_NONFAULTING | GTF_IND_TLS_REF | \
GTF_IND_UNALIGNED | GTF_IND_INVARIANT | GTF_IND_ARR_INDEX)
GTF_IND_UNALIGNED | GTF_IND_INVARIANT | GTF_IND_ARR_INDEX | GTF_IND_TGT_NOT_HEAP)

#define GTF_CLS_VAR_VOLATILE 0x40000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_IND_VOLATILE
#define GTF_CLS_VAR_INITCLASS 0x20000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_FLD_INITCLASS
Expand Down Expand Up @@ -1807,8 +1808,11 @@ struct GenTree
while (node->gtOper == GT_COMMA)
{
node = node->gtGetOp2();
assert(node->gtType == oldType);
node->gtType = newType;
if (node->gtType != newType)
{
assert(node->gtType == oldType);
node->gtType = newType;
}
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/src/jit/jitgcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ class GCInfo
regPtrDsc* genStackPtrFirst,
regPtrDsc* genStackPtrLast);

// Update the flags for a stack allocated object
void gcUpdateFlagForStackAllocatedObjects(GcSlotFlags& flags);

#endif

#if MEASURE_PTRTAB_SIZE
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/src/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16857,14 +16857,10 @@ void Compiler::fgMorph()
// local variable allocation on the stack.
ObjectAllocator objectAllocator(this); // PHASE_ALLOCATE_OBJECTS

// TODO-ObjectStackAllocation: Enable the optimization for architectures using
// JIT32_GCENCODER (i.e., x86).
#ifndef JIT32_GCENCODER
if (JitConfig.JitObjectStackAllocation() && opts.OptimizationEnabled())
{
objectAllocator.EnableObjectStackAllocation();
}
#endif // JIT32_GCENCODER

objectAllocator.Run();

Expand Down
Loading

0 comments on commit d135221

Please sign in to comment.