break;
case GT_FIELD:
-
- if (tree->gtFlags & GTF_FLD_NULLCHECK)
- {
- chars += printf("[FLD_NULLCHECK]");
- }
if (tree->gtFlags & GTF_FLD_VOLATILE)
{
chars += printf("[FLD_VOLATILE]");
{
chars += printf("[IND_INVARIANT]");
}
- if (tree->gtFlags & GTF_IND_ARR_LEN)
- {
- chars += printf("[IND_ARR_INDEX]");
- }
break;
case GT_CLS_VAR:
GenTree* gtNewCodeRef(BasicBlock* block);
- GenTree* gtNewFieldRef(
- var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0, bool nullcheck = false);
+ GenTree* gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
* A little helper to create a data member reference node.
*/
-inline GenTree* Compiler::gtNewFieldRef(
- var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset, bool nullcheck)
+inline GenTree* Compiler::gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset)
{
#if SMALL_TREE_NODES
/* 'GT_FIELD' nodes may later get transformed into 'GT_IND' */
tree->gtField.gtFieldLookup.addr = nullptr;
#endif
- if (nullcheck)
- {
- tree->gtFlags |= GTF_FLD_NULLCHECK;
- }
-
// If "obj" is the address of a local, note that a field of that struct local has been accessed.
if (obj != nullptr && obj->OperGet() == GT_ADDR && varTypeIsStruct(obj->gtOp.gtOp1) &&
obj->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
#define GTF_NOP_DEATH 0x40000000 // GT_NOP -- operand dies here
-#define GTF_FLD_NULLCHECK 0x80000000 // GT_FIELD -- need to nullcheck the "this" pointer
#define GTF_FLD_VOLATILE 0x40000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_IND_VOLATILE
#define GTF_FLD_INITCLASS 0x20000000 // GT_FIELD/GT_CLS_VAR -- field access requires preceding class/static init helper
#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_ARR_LEN 0x80000000 // GT_IND -- the indirection represents an array length (of the REF
- // contribution to its argument).
#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.
op1 = impPopStack().val;
GenTree* thisptr = newobjThis;
CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
- GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, thisptr, 0, false);
+ GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, thisptr, 0);
GenTree* assign = gtNewAssignNode(field, op1);
GenTree* byReferenceStruct = gtCloneExpr(thisptr->gtGetOp1());
assert(byReferenceStruct != nullptr);
{
op1 = impPopStack().val;
CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
- GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, op1, 0, false);
+ GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, op1, 0);
retNode = field;
break;
}
// Bounds check
CORINFO_FIELD_HANDLE lengthHnd = info.compCompHnd->getFieldInClass(clsHnd, 1);
const unsigned lengthOffset = info.compCompHnd->getFieldOffset(lengthHnd);
- GenTree* length = gtNewFieldRef(TYP_INT, lengthHnd, ptrToSpan, lengthOffset, false);
+ GenTree* length = gtNewFieldRef(TYP_INT, lengthHnd, ptrToSpan, lengthOffset);
GenTree* boundsCheck = new (this, GT_ARR_BOUNDS_CHECK)
GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, index, length, SCK_RNGCHK_FAIL);
GenTree* mulNode = gtNewOperNode(GT_MUL, TYP_I_IMPL, indexIntPtr, sizeofNode);
CORINFO_FIELD_HANDLE ptrHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
const unsigned ptrOffset = info.compCompHnd->getFieldOffset(ptrHnd);
- GenTree* data = gtNewFieldRef(TYP_BYREF, ptrHnd, ptrToSpanClone, ptrOffset, false);
+ GenTree* data = gtNewFieldRef(TYP_BYREF, ptrHnd, ptrToSpanClone, ptrOffset);
GenTree* result = gtNewOperNode(GT_ADD, TYP_BYREF, data, mulNode);
// Prepare result
case CORINFO_FIELD_INSTANCE_WITH_BASE:
#endif
{
- bool nullcheckNeeded = false;
-
obj = impCheckForNullPointer(obj);
- if (isLoadAddress && (obj->gtType == TYP_BYREF) && fgAddrCouldBeNull(obj))
- {
- nullcheckNeeded = true;
- }
-
// If the object is a struct, what we really want is
// for the field to operate on the address of the struct.
if (!varTypeGCtype(obj->TypeGet()) && impIsValueType(tiObj))
}
/* Create the data member node */
- op1 = gtNewFieldRef(lclTyp, resolvedToken.hField, obj, fieldInfo.offset, nullcheckNeeded);
+ op1 = gtNewFieldRef(lclTyp, resolvedToken.hField, obj, fieldInfo.offset);
#ifdef FEATURE_READYTORUN_COMPILER
if (fieldInfo.fieldAccessor == CORINFO_FIELD_INSTANCE_WITH_BASE)
op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1,
gtNewIconNode(OFFSETOF__CORINFO_Array__length, TYP_I_IMPL));
op1 = gtNewIndir(TYP_INT, op1);
- op1->gtFlags |= GTF_IND_ARR_LEN;
}
/* Push the result back on the stack */
}
tree->SetOper(GT_IND);
- // The GTF_FLD_NULLCHECK is the same bit as GTF_IND_ARR_LEN.
- // We must clear it when we transform the node.
- // TODO-Cleanup: It appears that the GTF_FLD_NULLCHECK flag is never checked, and note
- // that the logic above does its own checking to determine whether a nullcheck is needed.
- tree->gtFlags &= ~GTF_IND_ARR_LEN;
tree->gtOp.gtOp1 = addr;
return fgMorphSmpOp(tree);
}
}
noway_assert(tree->gtOper == GT_IND);
- // The GTF_FLD_NULLCHECK is the same bit as GTF_IND_ARR_LEN.
- // We must clear it when we transform the node.
- // TODO-Cleanup: It appears that the GTF_FLD_NULLCHECK flag is never checked, and note
- // that the logic above does its own checking to determine whether a nullcheck is needed.
- tree->gtFlags &= ~GTF_IND_ARR_LEN;
GenTree* res = fgMorphSmpOp(tree);
fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp.GetLiberal(), fldSeq);
}
}
- else if (tree->gtFlags & GTF_IND_ARR_LEN)
- {
- // It's an array length. The argument is the sum of an array ref with some integer values...
- ValueNum arrRefLib = vnStore->VNForRefInAddr(tree->gtOp.gtOp1->gtVNPair.GetLiberal());
- ValueNum arrRefCons = vnStore->VNForRefInAddr(tree->gtOp.gtOp1->gtVNPair.GetConservative());
-
- assert(vnStore->TypeOfVN(arrRefLib) == TYP_REF || vnStore->TypeOfVN(arrRefLib) == TYP_BYREF);
- if (vnStore->IsVNConstant(arrRefLib))
- {
- // (or in weird cases, a REF or BYREF constant, in which case the result is an exception).
- tree->gtVNPair.SetLiberal(
- vnStore->VNWithExc(ValueNumStore::VNForVoid(),
- vnStore->VNExcSetSingleton(
- vnStore->VNForFunc(TYP_REF, VNF_NullPtrExc, arrRefLib))));
- }
- else
- {
- tree->gtVNPair.SetLiberal(vnStore->VNForFunc(TYP_INT, VNFunc(GT_ARR_LENGTH), arrRefLib));
- }
- assert(vnStore->TypeOfVN(arrRefCons) == TYP_REF || vnStore->TypeOfVN(arrRefCons) == TYP_BYREF);
- if (vnStore->IsVNConstant(arrRefCons))
- {
- // (or in weird cases, a REF or BYREF constant, in which case the result is an exception).
- tree->gtVNPair.SetConservative(
- vnStore->VNWithExc(ValueNumStore::VNForVoid(),
- vnStore->VNExcSetSingleton(
- vnStore->VNForFunc(TYP_REF, VNF_NullPtrExc, arrRefCons))));
- }
- else
- {
- tree->gtVNPair.SetConservative(vnStore->VNForFunc(TYP_INT, VNFunc(GT_ARR_LENGTH), arrRefCons));
- }
- }
-
// In general we skip GT_IND nodes on that are the LHS of an assignment. (We labeled these earlier.)
// We will "evaluate" this as part of the assignment.
else if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)