@@ -2979,84 +2979,6 @@ GenTree* Compiler::impInlineUnboxNullable(CORINFO_CLASS_HANDLE nullableCls, GenT
29792979 return gtNewLclvNode(resultTmp, TYP_STRUCT);
29802980}
29812981
2982- //------------------------------------------------------------------------
2983- // impStoreNullableFields: create a Nullable<T> object and store
2984- // 'hasValue' (always true) and the given value for 'value' field
2985- //
2986- // Arguments:
2987- // nullableCls - class handle for the Nullable<T> class
2988- // value - value to store in 'value' field
2989- //
2990- // Return Value:
2991- // A local node representing the created Nullable<T> object
2992- //
2993- GenTree* Compiler::impStoreNullableFields(CORINFO_CLASS_HANDLE nullableCls, GenTree* value)
2994- {
2995- assert(info.compCompHnd->isNullableType(nullableCls) == TypeCompareState::Must);
2996-
2997- CORINFO_FIELD_HANDLE valueFldHnd = info.compCompHnd->getFieldInClass(nullableCls, 1);
2998- CORINFO_CLASS_HANDLE valueStructCls;
2999- var_types valueType = JITtype2varType(info.compCompHnd->getFieldType(valueFldHnd, &valueStructCls));
3000-
3001- // We still make some assumptions about the layout of Nullable<T> in JIT
3002- static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
3003- unsigned hasValOffset = OFFSETOF__CORINFO_NullableOfT__hasValue;
3004- unsigned valueOffset = info.compCompHnd->getFieldOffset(valueFldHnd);
3005-
3006- // Define the resulting Nullable<T> local
3007- unsigned resultTmp = lvaGrabTemp(true DEBUGARG("Nullable<T> tmp"));
3008- lvaSetStruct(resultTmp, nullableCls, false);
3009-
3010- // Now do two stores:
3011- GenTree* hasValueStore = gtNewStoreLclFldNode(resultTmp, TYP_UBYTE, hasValOffset, gtNewIconNode(1));
3012- ClassLayout* layout = valueType == TYP_STRUCT ? typGetObjLayout(valueStructCls) : nullptr;
3013- GenTree* valueStore = gtNewStoreLclFldNode(resultTmp, valueType, layout, valueOffset, value);
3014-
3015- impAppendTree(hasValueStore, CHECK_SPILL_ALL, impCurStmtDI);
3016- impAppendTree(valueStore, CHECK_SPILL_ALL, impCurStmtDI);
3017- return gtNewLclvNode(resultTmp, TYP_STRUCT);
3018- }
3019-
3020- //------------------------------------------------------------------------
3021- // impLoadNullableFields: get 'hasValue' and 'value' field loads for Nullable<T> object
3022- //
3023- // Arguments:
3024- // nullableObj - tree representing the Nullable<T> object
3025- // nullableCls - class handle for the Nullable<T> class
3026- // hasValueFld - pointer to store the 'hasValue' field load tree
3027- // valueFld - pointer to store the 'value' field load tree
3028- //
3029- void Compiler::impLoadNullableFields(GenTree* nullableObj,
3030- CORINFO_CLASS_HANDLE nullableCls,
3031- GenTree** hasValueFld,
3032- GenTree** valueFld)
3033- {
3034- assert(info.compCompHnd->isNullableType(nullableCls) == TypeCompareState::Must);
3035-
3036- CORINFO_FIELD_HANDLE valueFldHnd = info.compCompHnd->getFieldInClass(nullableCls, 1);
3037- CORINFO_CLASS_HANDLE valueStructCls;
3038- var_types valueType = JITtype2varType(info.compCompHnd->getFieldType(valueFldHnd, &valueStructCls));
3039- ClassLayout* valueLayout = valueType == TYP_STRUCT ? typGetObjLayout(valueStructCls) : nullptr;
3040-
3041- static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
3042- unsigned hasValOffset = OFFSETOF__CORINFO_NullableOfT__hasValue;
3043- unsigned valueOffset = info.compCompHnd->getFieldOffset(valueFldHnd);
3044-
3045- unsigned objTmp;
3046- if (!nullableObj->OperIs(GT_LCL_VAR))
3047- {
3048- objTmp = lvaGrabTemp(true DEBUGARG("Nullable<T> tmp"));
3049- impStoreToTemp(objTmp, nullableObj, CHECK_SPILL_ALL);
3050- }
3051- else
3052- {
3053- objTmp = nullableObj->AsLclVarCommon()->GetLclNum();
3054- }
3055-
3056- *hasValueFld = gtNewLclFldNode(objTmp, TYP_UBYTE, hasValOffset);
3057- *valueFld = gtNewLclFldNode(objTmp, valueType, valueOffset, valueLayout);
3058- }
3059-
30602982//------------------------------------------------------------------------
30612983// impBoxPatternMatch: match and import common box idioms
30622984//
@@ -3122,40 +3044,6 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken,
31223044 {
31233045 optimize = true;
31243046 }
3125- //
3126- // Also, try to optimize (T)(object)nullableT
3127- //
3128- else if (!eeIsSharedInst(unboxResolvedToken.hClass) &&
3129- (info.compCompHnd->isNullableType(pResolvedToken->hClass) == TypeCompareState::Must) &&
3130- (info.compCompHnd->getTypeForBox(pResolvedToken->hClass) == unboxResolvedToken.hClass))
3131- {
3132- GenTree* hasValueFldTree;
3133- GenTree* valueFldTree;
3134- impLoadNullableFields(impPopStack().val, pResolvedToken->hClass, &hasValueFldTree,
3135- &valueFldTree);
3136-
3137- // Push "hasValue == 0 ? throw new NullReferenceException() : NOP" qmark
3138- GenTree* fallback = gtNewHelperCallNode(CORINFO_HELP_THROWNULLREF, TYP_VOID);
3139- GenTree* cond = gtNewOperNode(GT_EQ, TYP_INT, hasValueFldTree, gtNewIconNode(0));
3140- GenTreeColon* colon = gtNewColonNode(TYP_VOID, fallback, gtNewNothingNode());
3141- GenTree* qmark = gtNewQmarkNode(TYP_VOID, cond, colon);
3142- impAppendTree(qmark, CHECK_SPILL_ALL, impCurStmtDI);
3143-
3144- // Now push the value field
3145- impPushOnStack(valueFldTree, typeInfo(valueFldTree->TypeGet()));
3146- optimize = true;
3147- }
3148- //
3149- // Vice versa, try to optimize (T?)(object)nonNullableT
3150- //
3151- else if (!eeIsSharedInst(pResolvedToken->hClass) &&
3152- (info.compCompHnd->isNullableType(unboxResolvedToken.hClass) == TypeCompareState::Must) &&
3153- (info.compCompHnd->getTypeForBox(unboxResolvedToken.hClass) == pResolvedToken->hClass))
3154- {
3155- GenTree* result = impStoreNullableFields(unboxResolvedToken.hClass, impPopStack().val);
3156- impPushOnStack(result, typeInfo(result->TypeGet()));
3157- optimize = true;
3158- }
31593047 }
31603048
31613049 if (optimize)
@@ -5814,7 +5702,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree(GenTree* op1,
58145702 // We can convert constant-ish tokens of nullable to its underlying type.
58155703 // However, when the type is shared generic parameter like Nullable<Struct<__Canon>>, the actual type will require
58165704 // runtime lookup. It's too complex to add another level of indirection in op2, fallback to the cast helper instead.
5817- if (isClassExact && !eeIsSharedInst( pResolvedToken->hClass))
5705+ if (isClassExact && !(info.compCompHnd->getClassAttribs( pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST ))
58185706 {
58195707 CORINFO_CLASS_HANDLE hClass = info.compCompHnd->getTypeForBox(pResolvedToken->hClass);
58205708 if (hClass != pResolvedToken->hClass)
@@ -5860,7 +5748,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree(GenTree* op1,
58605748 !compCurBB->isRunRarely())
58615749 {
58625750 // It doesn't make sense to instrument "x is T" or "(T)x" for shared T
5863- if (!eeIsSharedInst( pResolvedToken->hClass))
5751+ if ((info.compCompHnd->getClassAttribs( pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) == 0 )
58645752 {
58655753 HandleHistogramProfileCandidateInfo* pInfo =
58665754 new (this, CMK_Inlining) HandleHistogramProfileCandidateInfo;
@@ -9736,7 +9624,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
97369624 CORINFO_FIELD_INFO fi;
97379625 eeGetFieldInfo(&fldToken, CORINFO_ACCESS_SET, &fi);
97389626 unsigned flagsToCheck = CORINFO_FLG_FIELD_STATIC | CORINFO_FLG_FIELD_FINAL;
9739- if (((fi.fieldFlags & flagsToCheck) == flagsToCheck) && !eeIsSharedInst(info.compClassHnd))
9627+ if (((fi.fieldFlags & flagsToCheck) == flagsToCheck) &&
9628+ ((info.compCompHnd->getClassAttribs(info.compClassHnd) & CORINFO_FLG_SHAREDINST) == 0))
97409629 {
97419630#ifdef FEATURE_READYTORUN
97429631 if (opts.IsReadyToRun())
0 commit comments