Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Initial implementation of object stack allocation #20814

Merged
merged 4 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6107,12 +6107,13 @@ class Compiler
}
};

#define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
#define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
#define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
#define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
#define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
#define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
#define OMF_HAS_NEWARRAY 0x00000001 // Method contains 'new' of an array
#define OMF_HAS_NEWOBJ 0x00000002 // Method contains 'new' of an object type.
#define OMF_HAS_ARRAYREF 0x00000004 // Method contains array element loads or stores.
#define OMF_HAS_VTABLEREF 0x00000008 // Method contains method table reference.
#define OMF_HAS_NULLCHECK 0x00000010 // Method contains null check.
#define OMF_HAS_FATPOINTER 0x00000020 // Method contains call, that needs fat pointer transformation.
#define OMF_HAS_OBJSTACKALLOC 0x00000040 // Method contains an object allocated on the stack.

bool doesMethodHaveFatPointer()
{
Expand Down
1 change: 1 addition & 0 deletions src/jit/compmemkind.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ CompMemKindMacro(Unknown)
CompMemKindMacro(RangeCheck)
CompMemKindMacro(CopyProp)
CompMemKindMacro(SideEffects)
CompMemKindMacro(ObjectAllocator)
//clang-format on

#undef CompMemKindMacro
29 changes: 29 additions & 0 deletions src/jit/gcencode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4245,6 +4245,7 @@ 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 @@ -4344,6 +4345,7 @@ void GCInfo::gcMakeRegPtrTable(
{
flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
}
gcUpdateFlagForStackAllocatedObjects(flags);

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

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

if ((lowBits & pinned_OFFSET_FLAG) != 0)
{
flags = (GcSlotFlags)(flags | GC_SLOT_PINNED);
Expand Down Expand Up @@ -4920,6 +4925,30 @@ 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
9 changes: 8 additions & 1 deletion src/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10769,7 +10769,14 @@ void Compiler::gtDispTree(GenTree* tree,
switch (tree->gtOper)
{
case GT_FIELD:
printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
if (FieldSeqStore::IsPseudoField(tree->gtField.gtFldHnd))
{
printf(" #PseudoField:0x%x", tree->gtField.gtFldOffset);
}
else
{
printf(" %s", eeGetFieldName(tree->gtField.gtFldHnd), 0);
}

if (tree->gtField.gtFldObj && !topOnly)
{
Expand Down
1 change: 1 addition & 0 deletions src/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ CONFIG_STRING(JitInlineReplayFile, W("JitInlineReplayFile"))
#endif // defined(DEBUG) || defined(INLINE_DATA)

CONFIG_INTEGER(JitInlinePolicyModel, W("JitInlinePolicyModel"), 0)
CONFIG_INTEGER(JitObjectStackAllocation, W("JitObjectStackAllocation"), 0)

CONFIG_INTEGER(JitEECallTimingInfo, W("JitEECallTimingInfo"), 0)

Expand Down
3 changes: 3 additions & 0 deletions src/jit/jitgcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ 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
73 changes: 49 additions & 24 deletions src/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,12 @@ void Compiler::StructPromotionHelper::CheckRetypedAsScalar(CORINFO_FIELD_HANDLE
//
bool Compiler::StructPromotionHelper::CanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd)
{
assert(compiler->eeIsValueClass(typeHnd));
if (!compiler->eeIsValueClass(typeHnd))
{
// TODO-ObjectStackAllocation: Enable promotion of fields of stack-allocated objects.
return false;
}

if (structPromotionInfo.typeHnd == typeHnd)
{
// Asking for the same type of struct as the last time.
Expand Down Expand Up @@ -2460,49 +2465,69 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool
}
if (varDsc->lvExactSize == 0)
{
varDsc->lvExactSize = info.compCompHnd->getClassSize(typeHnd);
BOOL isValueClass = info.compCompHnd->isValueClass(typeHnd);

if (isValueClass)
{
varDsc->lvExactSize = info.compCompHnd->getClassSize(typeHnd);
}
else
{
varDsc->lvExactSize = info.compCompHnd->getHeapClassSize(typeHnd);
}

size_t lvSize = varDsc->lvSize();
assert((lvSize % TARGET_POINTER_SIZE) ==
0); // The struct needs to be a multiple of TARGET_POINTER_SIZE bytes for getClassGClayout() to be valid.
varDsc->lvGcLayout = getAllocator(CMK_LvaTable).allocate<BYTE>(lvSize / TARGET_POINTER_SIZE);
unsigned numGCVars;
var_types simdBaseType = TYP_UNKNOWN;
varDsc->lvType = impNormStructType(typeHnd, varDsc->lvGcLayout, &numGCVars, &simdBaseType);
if (isValueClass)
{
varDsc->lvType = impNormStructType(typeHnd, varDsc->lvGcLayout, &numGCVars, &simdBaseType);
}
else
{
numGCVars = info.compCompHnd->getClassGClayout(typeHnd, varDsc->lvGcLayout);
}

// We only save the count of GC vars in a struct up to 7.
if (numGCVars >= 8)
{
numGCVars = 7;
}
varDsc->lvStructGcCount = numGCVars;
#if FEATURE_SIMD
if (simdBaseType != TYP_UNKNOWN)

if (isValueClass)
{
assert(varTypeIsSIMD(varDsc));
varDsc->lvSIMDType = true;
varDsc->lvBaseType = simdBaseType;
}
#if FEATURE_SIMD
if (simdBaseType != TYP_UNKNOWN)
{
assert(varTypeIsSIMD(varDsc));
varDsc->lvSIMDType = true;
varDsc->lvBaseType = simdBaseType;
}
#endif // FEATURE_SIMD
#ifdef FEATURE_HFA
// for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
{
var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
if (varTypeIsFloating(hfaType))
// for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat
if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES)
{
varDsc->_lvIsHfa = true;
varDsc->lvSetHfaTypeIsFloat(hfaType == TYP_FLOAT);

// hfa variables can never contain GC pointers
assert(varDsc->lvStructGcCount == 0);
// The size of this struct should be evenly divisible by 4 or 8
assert((varDsc->lvExactSize % genTypeSize(hfaType)) == 0);
// The number of elements in the HFA should fit into our MAX_ARG_REG_COUNT limit
assert((varDsc->lvExactSize / genTypeSize(hfaType)) <= MAX_ARG_REG_COUNT);
var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF
if (varTypeIsFloating(hfaType))
{
varDsc->_lvIsHfa = true;
varDsc->lvSetHfaTypeIsFloat(hfaType == TYP_FLOAT);

// hfa variables can never contain GC pointers
assert(varDsc->lvStructGcCount == 0);
// The size of this struct should be evenly divisible by 4 or 8
assert((varDsc->lvExactSize % genTypeSize(hfaType)) == 0);
// The number of elements in the HFA should fit into our MAX_ARG_REG_COUNT limit
assert((varDsc->lvExactSize / genTypeSize(hfaType)) <= MAX_ARG_REG_COUNT);
}
}
}
#endif // FEATURE_HFA
}
}
else
{
Expand Down
10 changes: 10 additions & 0 deletions src/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16733,6 +16733,16 @@ void Compiler::fgMorph()
// Transform each GT_ALLOCOBJ node into either an allocation helper call or
// 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.MinOpts() && !opts.compDbgCode)
{
objectAllocator.EnableObjectStackAllocation();
}
#endif // JIT32_GCENCODER

objectAllocator.Run();

/* Add any internal blocks/trees we may need */
Expand Down
Loading