diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp index a86197994e377d..987a81146667c8 100644 --- a/src/coreclr/jit/objectalloc.cpp +++ b/src/coreclr/jit/objectalloc.cpp @@ -71,7 +71,7 @@ ObjectAllocator::ObjectAllocator(Compiler* comp) // bool ObjectAllocator::IsTrackedType(var_types type) { - const bool isTrackableScalar = (type == TYP_REF) || (genActualType(type) == TYP_I_IMPL) || (type == TYP_BYREF); + const bool isTrackableScalar = (type == TYP_REF) || (type == TYP_BYREF); return isTrackableScalar; } @@ -1579,12 +1579,19 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack* parent switch (parent->OperGet()) { - // Update the connection graph if we are storing to a local. - // For all other stores we mark the local as escaping. case GT_STORE_LCL_VAR: { - // Add an edge to the connection graph. const unsigned int dstLclNum = parent->AsLclVar()->GetLclNum(); + + // If we're not tracking stores to this local, the value + // does not escape. + if (!IsTrackedLocal(dstLclNum)) + { + canLclVarEscapeViaParentStack = false; + break; + } + + // Add an edge to the connection graph. const unsigned int srcLclNum = lclNum; AddConnGraphEdge(dstLclNum, srcLclNum); @@ -1626,13 +1633,25 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack* parent case GT_COLON: case GT_QMARK: case GT_ADD: - case GT_SUB: case GT_FIELD_ADDR: // Check whether the local escapes via its grandparent. ++parentIndex; keepChecking = true; break; + case GT_SUB: + // Sub of two GC refs is no longer a GC ref. + if (!parent->TypeIs(TYP_BYREF, TYP_REF)) + { + canLclVarEscapeViaParentStack = false; + break; + } + + // Check whether the local escapes higher up + ++parentIndex; + keepChecking = true; + break; + case GT_BOX: isCopy = wasCopy; ++parentIndex; @@ -1787,7 +1806,6 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree, ArrayStack* p FALLTHROUGH; case GT_QMARK: case GT_ADD: - case GT_SUB: case GT_FIELD_ADDR: case GT_INDEX_ADDR: case GT_BOX: @@ -1799,6 +1817,33 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree, ArrayStack* p keepChecking = true; break; + case GT_SUB: + { + // Parent type can be TYP_I_IMPL, TYP_BYREF. + // But not TYP_REF. + // + var_types parentType = parent->TypeGet(); + assert(parentType != TYP_REF); + + // New type can be TYP_I_IMPL, TYP_BYREF. + // But TYP_BYREF only if parent is also + // + if (parentType != newType) + { + // We must be retyping TYP_BYREF to TYP_I_IMPL. + // + assert(newType == TYP_I_IMPL); + assert(parentType == TYP_BYREF); + parent->ChangeType(newType); + + // Propgate that upwards. + // + ++parentIndex; + keepChecking = true; + } + break; + } + case GT_COLON: { GenTree* const lhs = parent->AsOp()->gtGetOp1();