Skip to content

Commit

Permalink
Fix ldelem[a]/stelem/cpobj/ldobj/stobj <pointer type> import (#71679)
Browse files Browse the repository at this point in the history
  • Loading branch information
SingleAccretion authored Jul 28, 2022
1 parent 8e1c9c1 commit 11e3d1b
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 131 deletions.
182 changes: 52 additions & 130 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4148,12 +4148,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
switch (ni)
{
case NI_System_Type_get_IsValueType:
retNode = gtNewIconNode(
(eeIsValueClass(hClass) &&
// pointers are not value types (e.g. typeof(int*).IsValueType is false)
info.compCompHnd->asCorInfoType(hClass) != CORINFO_TYPE_PTR)
? 1
: 0);
retNode = gtNewIconNode(eeIsValueClass(hClass) ? 1 : 0);
break;
case NI_System_Type_get_IsByRefLike:
retNode = gtNewIconNode(
Expand Down Expand Up @@ -13752,70 +13747,57 @@ void Compiler::impImportBlockCode(BasicBlock* block)
goto APPEND;

case CEE_LDELEMA:
{
assertImp(sz == sizeof(unsigned));

_impResolveToken(CORINFO_TOKENKIND_Class);

JITDUMP(" %08X", resolvedToken.token);

ldelemClsHnd = resolvedToken.hClass;
lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(ldelemClsHnd));

// If it's a value class array we just do a simple address-of
if (eeIsValueClass(ldelemClsHnd))
{
CorInfoType cit = info.compCompHnd->getTypeForPrimitiveValueClass(ldelemClsHnd);
if (cit == CORINFO_TYPE_UNDEF)
{
lclTyp = TYP_STRUCT;
}
else
{
lclTyp = JITtype2varType(cit);
}
goto ARR_LD;
}

// Similarly, if its a readonly access, we can do a simple address-of
// without doing a runtime type-check
if (prefixFlags & PREFIX_READONLY)
// If it's a value class / pointer array, or a readonly access, we don't need a type check.
// TODO-CQ: adapt "impCanSkipCovariantStoreCheck" to handle "ldelema"s and call it here to
// skip using the helper in more cases.
if ((lclTyp != TYP_REF) || ((prefixFlags & PREFIX_READONLY) != 0))
{
lclTyp = TYP_REF;
goto ARR_LD;
}

// Otherwise we need the full helper function with run-time type check
op1 = impTokenToHandle(&resolvedToken);
if (op1 == nullptr)
{ // compDonotInline()
GenTree* type = impTokenToHandle(&resolvedToken);
if (type == nullptr)
{
assert(compDonotInline());
return;
}

{
GenTree* type = op1;
GenTree* index = impPopStack().val;
GenTree* arr = impPopStack().val;
GenTree* index = impPopStack().val;
GenTree* arr = impPopStack().val;

#ifdef TARGET_64BIT
// The CLI Spec allows an array to be indexed by either an int32 or a native int.
// The array helper takes a native int for array length.
// So if we have an int, explicitly extend it to be a native int.
if (genActualType(index->TypeGet()) != TYP_I_IMPL)
// The CLI Spec allows an array to be indexed by either an int32 or a native int.
// The array helper takes a native int for array length.
// So if we have an int, explicitly extend it to be a native int.
if (genActualType(index->TypeGet()) != TYP_I_IMPL)
{
if (index->IsIntegralConst())
{
if (index->IsIntegralConst())
{
index->gtType = TYP_I_IMPL;
}
else
{
bool isUnsigned = false;
index = gtNewCastNode(TYP_I_IMPL, index, isUnsigned, TYP_I_IMPL);
}
index->gtType = TYP_I_IMPL;
}
else
{
bool isUnsigned = false;
index = gtNewCastNode(TYP_I_IMPL, index, isUnsigned, TYP_I_IMPL);
}
#endif // TARGET_64BIT
op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type);
}
#endif // TARGET_64BIT

op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type);
impPushOnStack(op1, tiRetVal);
break;
}
break;

// ldelem for reference and value types
case CEE_LDELEM:
Expand All @@ -13826,21 +13808,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
JITDUMP(" %08X", resolvedToken.token);

ldelemClsHnd = resolvedToken.hClass;

// If it's a reference type or generic variable type
// then just generate code as though it's a ldelem.ref instruction
if (!eeIsValueClass(ldelemClsHnd))
{
lclTyp = TYP_REF;
opcode = CEE_LDELEM_REF;
}
else
{
CorInfoType jitTyp = info.compCompHnd->asCorInfoType(ldelemClsHnd);
lclTyp = JITtype2varType(jitTyp);
tiRetVal = verMakeTypeInfo(ldelemClsHnd); // precise type always needed for struct
tiRetVal.NormaliseForStack();
}
lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(ldelemClsHnd));
tiRetVal = verMakeTypeInfo(ldelemClsHnd);
tiRetVal.NormaliseForStack();
goto ARR_LD;

case CEE_LDELEM_I1:
Expand Down Expand Up @@ -13918,23 +13888,15 @@ void Compiler::impImportBlockCode(BasicBlock* block)
JITDUMP(" %08X", resolvedToken.token);

stelemClsHnd = resolvedToken.hClass;
lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(stelemClsHnd));

// If it's a reference type just behave as though it's a stelem.ref instruction
if (!eeIsValueClass(stelemClsHnd))
if (lclTyp != TYP_REF)
{
goto STELEM_REF_POST_VERIFY;
}

// Otherwise extract the type
{
CorInfoType jitTyp = info.compCompHnd->asCorInfoType(stelemClsHnd);
lclTyp = JITtype2varType(jitTyp);
goto ARR_ST;
}
FALLTHROUGH;

case CEE_STELEM_REF:
STELEM_REF_POST_VERIFY:

{
GenTree* value = impStackTop(0).val;
GenTree* index = impStackTop(1).val;
Expand Down Expand Up @@ -17370,20 +17332,16 @@ void Compiler::impImportBlockCode(BasicBlock* block)

JITDUMP(" %08X", resolvedToken.token);

if (!eeIsValueClass(resolvedToken.hClass))
lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(resolvedToken.hClass));

if (lclTyp != TYP_STRUCT)
{
op1 = impPopStack().val; // address to load from

impBashVarAddrsToI(op1);

assertImp(genActualType(op1->gtType) == TYP_I_IMPL || op1->gtType == TYP_BYREF);

op1 = gtNewOperNode(GT_IND, TYP_REF, op1);
op1->gtFlags |= GTF_EXCEPT | GTF_GLOB_REF;
op1 = gtNewIndir(lclTyp, op1);
op1->gtFlags |= GTF_GLOB_REF;

impPushOnStack(op1, typeInfo());
opcode = CEE_STIND_REF;
lclTyp = TYP_REF;
goto STIND;
}

Expand All @@ -17400,25 +17358,10 @@ void Compiler::impImportBlockCode(BasicBlock* block)

JITDUMP(" %08X", resolvedToken.token);

if (eeIsValueClass(resolvedToken.hClass))
{
lclTyp = TYP_STRUCT;
}
else
{
lclTyp = TYP_REF;
}

if (lclTyp == TYP_REF)
{
opcode = CEE_STIND_REF;
goto STIND;
}
lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(resolvedToken.hClass));

CorInfoType jitTyp = info.compCompHnd->asCorInfoType(resolvedToken.hClass);
if (impIsPrimitive(jitTyp))
if (lclTyp != TYP_STRUCT)
{
lclTyp = JITtype2varType(jitTyp);
goto STIND;
}

Expand Down Expand Up @@ -17485,39 +17428,19 @@ void Compiler::impImportBlockCode(BasicBlock* block)
JITDUMP(" %08X", resolvedToken.token);

OBJ:

lclTyp = JITtype2varType(info.compCompHnd->asCorInfoType(resolvedToken.hClass));
tiRetVal = verMakeTypeInfo(resolvedToken.hClass);

if (eeIsValueClass(resolvedToken.hClass))
{
lclTyp = TYP_STRUCT;
}
else
if (lclTyp != TYP_STRUCT)
{
lclTyp = TYP_REF;
opcode = CEE_LDIND_REF;
goto LDIND;
}

op1 = impPopStack().val;

assertImp(op1->TypeGet() == TYP_BYREF || op1->TypeGet() == TYP_I_IMPL);
assertImp((genActualType(op1) == TYP_I_IMPL) || op1->TypeIs(TYP_BYREF));

CorInfoType jitTyp = info.compCompHnd->asCorInfoType(resolvedToken.hClass);
if (impIsPrimitive(jitTyp))
{
op1 = gtNewOperNode(GT_IND, JITtype2varType(jitTyp), op1);

// Could point anywhere, example a boxed class static int
op1->gtFlags |= GTF_GLOB_REF;
assertImp(varTypeIsArithmetic(op1->gtType));
}
else
{
// OBJ returns a struct
// and an inline argument which is the class token of the loaded obj
op1 = gtNewObjNode(resolvedToken.hClass, op1);
}
op1 = gtNewObjNode(resolvedToken.hClass, op1);
op1->gtFlags |= GTF_EXCEPT;

if (prefixFlags & PREFIX_UNALIGNED)
Expand Down Expand Up @@ -17830,10 +17753,10 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)
impBashVarAddrsToI(op2);
op2 = impImplicitIorI4Cast(op2, info.compRetType);
op2 = impImplicitR4orR8Cast(op2, info.compRetType);
// Note that we allow TYP_I_IMPL<->TYP_BYREF transformation, but only TYP_I_IMPL<-TYP_REF.

assertImp((genActualType(op2->TypeGet()) == genActualType(info.compRetType)) ||
((op2->TypeGet() == TYP_I_IMPL) && TypeIs(info.compRetType, TYP_BYREF)) ||
(op2->TypeIs(TYP_BYREF, TYP_REF) && (info.compRetType == TYP_I_IMPL)) ||
((op2->TypeGet() == TYP_I_IMPL) && (info.compRetType == TYP_BYREF)) ||
((op2->TypeGet() == TYP_BYREF) && (info.compRetType == TYP_I_IMPL)) ||
(varTypeIsFloating(op2->gtType) && varTypeIsFloating(info.compRetType)) ||
(varTypeIsStruct(op2) && varTypeIsStruct(info.compRetType)));

Expand Down Expand Up @@ -17887,9 +17810,8 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)
if (returnType != originalCallType)
{
// Allow TYP_BYREF to be returned as TYP_I_IMPL and vice versa.
// Allow TYP_REF to be returned as TYP_I_IMPL and NOT vice verse.
if ((TypeIs(returnType, TYP_BYREF, TYP_REF) && (originalCallType == TYP_I_IMPL)) ||
((returnType == TYP_I_IMPL) && TypeIs(originalCallType, TYP_BYREF)))
if (((returnType == TYP_BYREF) && (originalCallType == TYP_I_IMPL)) ||
((returnType == TYP_I_IMPL) && (originalCallType == TYP_BYREF)))
{
JITDUMP("Allowing return type mismatch: have %s, needed %s\n", varTypeName(returnType),
varTypeName(originalCallType));
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ ClassLayout* Compiler::typGetObjLayout(CORINFO_CLASS_HANDLE classHandle)

ClassLayout* ClassLayout::Create(Compiler* compiler, CORINFO_CLASS_HANDLE classHandle)
{
bool isValueClass = compiler->info.compCompHnd->isValueClass(classHandle);
bool isValueClass = compiler->eeIsValueClass(classHandle);
unsigned size;

if (isValueClass)
Expand Down
Loading

0 comments on commit 11e3d1b

Please sign in to comment.