@@ -9257,13 +9257,34 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
92579257 DoGetArrayDataReference ();
92589258 didIntrinsic = true ;
92599259 break ;
9260+
92609261#if INTERP_ILSTUBS
92619262 case NI_System_StubHelpers_GetStubContext:
92629263 OpStackSet<void *>(m_curStackHt, GetStubContext ());
92639264 OpStackTypeSet (m_curStackHt, InterpreterType (CORINFO_TYPE_NATIVEINT));
92649265 m_curStackHt++; didIntrinsic = true ;
92659266 break ;
92669267#endif // INTERP_ILSTUBS
9268+
9269+ case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences:
9270+ DoIsReferenceOrContainsReferences (reinterpret_cast <CORINFO_METHOD_HANDLE>(methToCall));
9271+ didIntrinsic = true ;
9272+ break ;
9273+
9274+ case NI_System_Threading_Interlocked_CompareExchange:
9275+ // Here and in other Interlocked.* intrinsics we use sigInfo.retType to be able
9276+ // to detect small-integer overloads.
9277+ didIntrinsic = DoInterlockedCompareExchange (sigInfo.retType );
9278+ break ;
9279+
9280+ case NI_System_Threading_Interlocked_Exchange:
9281+ didIntrinsic = DoInterlockedExchange (sigInfo.retType );
9282+ break ;
9283+
9284+ case NI_System_Threading_Interlocked_ExchangeAdd:
9285+ didIntrinsic = DoInterlockedExchangeAdd (sigInfo.retType );
9286+ break ;
9287+
92679288 default :
92689289#if INTERP_TRACING
92699290 InterlockedIncrement (&s_totalInterpCallsToIntrinsicsUnhandled);
@@ -10903,6 +10924,197 @@ void Interpreter::DoGetArrayDataReference()
1090310924 OpStackTypeSet (ind, InterpreterType (CORINFO_TYPE_BYREF));
1090410925}
1090510926
10927+ static bool HasByrefFields (MethodTable* pMT)
10928+ {
10929+ // Inspect all instance fields recursively
10930+ ApproxFieldDescIterator fieldIterator (pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
10931+ for (FieldDesc* pFD = fieldIterator.Next (); pFD != nullptr ; pFD = fieldIterator.Next ())
10932+ {
10933+ if (pFD->IsByRef ())
10934+ {
10935+ return true ;
10936+ }
10937+ if ((pFD->GetFieldType () == ELEMENT_TYPE_VALUETYPE &&
10938+ HasByrefFields (pFD->GetApproxFieldTypeHandleThrowing ().AsMethodTable ())))
10939+ {
10940+ return true ;
10941+ }
10942+ }
10943+ return false ;
10944+ }
10945+
10946+ void Interpreter::DoIsReferenceOrContainsReferences (CORINFO_METHOD_HANDLE method)
10947+ {
10948+ CONTRACTL{
10949+ THROWS;
10950+ GC_TRIGGERS;
10951+ MODE_COOPERATIVE;
10952+ } CONTRACTL_END;
10953+
10954+ CORINFO_SIG_INFO sigInfoFull;
10955+ {
10956+ GCX_PREEMP ();
10957+ m_interpCeeInfo.getMethodSig (method, & sigInfoFull, nullptr );
10958+ }
10959+
10960+ MethodTable* typeArg = GetMethodTableFromClsHnd (sigInfoFull.sigInst .methInst [0 ]);
10961+
10962+ bool containsGcPtrs = typeArg->ContainsPointers ();
10963+
10964+ // Return true for byref-like structs with ref fields (they might not have them)
10965+ if (!containsGcPtrs && typeArg->IsByRefLike ())
10966+ {
10967+ containsGcPtrs |= HasByrefFields (typeArg);
10968+ }
10969+
10970+ OpStackSet<BOOL>(m_curStackHt, containsGcPtrs);
10971+ OpStackTypeSet (m_curStackHt, InterpreterType (CORINFO_TYPE_INT));
10972+ m_curStackHt++;
10973+ }
10974+
10975+ bool Interpreter::DoInterlockedCompareExchange (CorInfoType retType)
10976+ {
10977+ CONTRACTL{
10978+ THROWS;
10979+ GC_TRIGGERS;
10980+ MODE_COOPERATIVE;
10981+ } CONTRACTL_END;
10982+
10983+ // These CompareExchange are must-expand:
10984+ //
10985+ // long CompareExchange(ref long location1, long value, long comparand)
10986+ // int CompareExchange(ref int location1, int value, int comparand)
10987+ // ushort CompareExchange(ref ushort location1, ushort value, ushort comparand)
10988+ // byte CompareExchange(ref byte location1, byte value, byte comparand)
10989+ //
10990+ // Detect these by retType (signature)
10991+ unsigned comparandInd = m_curStackHt - 1 ;
10992+ unsigned valueInd = m_curStackHt - 2 ;
10993+ unsigned locationInd = m_curStackHt - 3 ;
10994+ switch (retType)
10995+ {
10996+ case CORINFO_TYPE_LONG:
10997+ m_curStackHt -= 3 ;
10998+ OpStackSet<int64_t >(m_curStackHt, InterlockedCompareExchange64 (
10999+ OpStackGet<int64_t *>(locationInd),
11000+ OpStackGet<int64_t >(valueInd),
11001+ OpStackGet<int64_t >(comparandInd)));
11002+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11003+ m_curStackHt++;
11004+ return true ;
11005+
11006+ case CORINFO_TYPE_INT:
11007+ m_curStackHt -= 3 ;
11008+ OpStackSet<LONG>(m_curStackHt, InterlockedCompareExchange (
11009+ OpStackGet<LONG*>(locationInd),
11010+ OpStackGet<LONG>(valueInd),
11011+ OpStackGet<LONG>(comparandInd)));
11012+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11013+ m_curStackHt++;
11014+ return true ;
11015+
11016+ case CORINFO_TYPE_SHORT:
11017+ case CORINFO_TYPE_BYTE:
11018+ NYI_INTERP (" TODO: Implement must-expand atomics for small types." );
11019+ return false ;
11020+
11021+ default :
11022+ // Non must-expand intrinsics
11023+ return false ;
11024+ }
11025+ }
11026+
11027+ bool Interpreter::DoInterlockedExchange (CorInfoType retType)
11028+ {
11029+ CONTRACTL{
11030+ THROWS;
11031+ GC_TRIGGERS;
11032+ MODE_COOPERATIVE;
11033+ } CONTRACTL_END;
11034+
11035+ // These Exchange are must-expand:
11036+ //
11037+ // long Exchange(ref long location1, long value)
11038+ // int Exchange(ref int location1, int value)
11039+ // ushort Exchange(ref ushort location1, ushort value)
11040+ // byte Exchange(ref byte location1, byte value)
11041+ //
11042+ // Detect these by retType (signature)
11043+ unsigned valueInd = m_curStackHt - 1 ;
11044+ unsigned locationInd = m_curStackHt - 2 ;
11045+ switch (retType)
11046+ {
11047+ case CORINFO_TYPE_LONG:
11048+ m_curStackHt -= 2 ;
11049+ OpStackSet<int64_t >(m_curStackHt, InterlockedExchange64 (
11050+ OpStackGet<int64_t *>(locationInd),
11051+ OpStackGet<int64_t >(valueInd)));
11052+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11053+ m_curStackHt++;
11054+ return true ;
11055+
11056+ case CORINFO_TYPE_INT:
11057+ m_curStackHt -= 2 ;
11058+ OpStackSet<LONG>(m_curStackHt, InterlockedExchange (
11059+ OpStackGet<LONG*>(locationInd),
11060+ OpStackGet<LONG>(valueInd)));
11061+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11062+ m_curStackHt++;
11063+ return true ;
11064+
11065+ case CORINFO_TYPE_SHORT:
11066+ case CORINFO_TYPE_BYTE:
11067+ NYI_INTERP (" TODO: Implement must-expand Exchange for small types." );
11068+ return false ;
11069+
11070+ default :
11071+ // Non must-expand intrinsics
11072+ return false ;
11073+ }
11074+ }
11075+
11076+ bool Interpreter::DoInterlockedExchangeAdd (CorInfoType retType)
11077+ {
11078+ CONTRACTL{
11079+ THROWS;
11080+ GC_TRIGGERS;
11081+ MODE_COOPERATIVE;
11082+ } CONTRACTL_END;
11083+
11084+ // These ExchangeAdd are must-expand:
11085+ //
11086+ // long ExchangeAdd(ref long location1, long value)
11087+ // int ExchangeAdd(ref int location1, int value)
11088+ //
11089+ // Detect these by retType (signature)
11090+ unsigned valueInd = m_curStackHt - 1 ;
11091+ unsigned locationInd = m_curStackHt - 2 ;
11092+ switch (retType)
11093+ {
11094+ case CORINFO_TYPE_LONG:
11095+ m_curStackHt -= 2 ;
11096+ OpStackSet<int64_t >(m_curStackHt, InterlockedExchangeAdd64 (
11097+ OpStackGet<int64_t *>(locationInd),
11098+ OpStackGet<int64_t >(valueInd)));
11099+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11100+ m_curStackHt++;
11101+ return true ;
11102+
11103+ case CORINFO_TYPE_INT:
11104+ m_curStackHt -= 2 ;
11105+ OpStackSet<LONG>(m_curStackHt, InterlockedExchangeAdd (
11106+ OpStackGet<LONG*>(locationInd),
11107+ OpStackGet<LONG>(valueInd)));
11108+ OpStackTypeSet (m_curStackHt, InterpreterType (retType));
11109+ m_curStackHt++;
11110+ return true ;
11111+
11112+ default :
11113+ // Non must-expand intrinsics
11114+ return false ;
11115+ }
11116+ }
11117+
1090611118void Interpreter::RecordConstrainedCall ()
1090711119{
1090811120 CONTRACTL {
@@ -11762,6 +11974,34 @@ Interpreter::InterpreterNamedIntrinsics Interpreter::getNamedIntrinsicID(CEEInfo
1176211974 }
1176311975 }
1176411976 }
11977+ else if (strcmp (namespaceName, " CompilerServices" ) == 0 )
11978+ {
11979+ if (strcmp (className, " RuntimeHelpers" ) == 0 )
11980+ {
11981+ if (strcmp (methodName, " IsReferenceOrContainsReferences" ) == 0 )
11982+ {
11983+ result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences;
11984+ }
11985+ }
11986+ }
11987+ }
11988+ else if (strncmp (namespaceName, " Threading" , 8 ) == 0 )
11989+ {
11990+ if (strcmp (className, " Interlocked" ) == 0 )
11991+ {
11992+ if (strcmp (methodName, " CompareExchange" ) == 0 )
11993+ {
11994+ result = NI_System_Threading_Interlocked_CompareExchange;
11995+ }
11996+ else if (strcmp (methodName, " Exchange" ) == 0 )
11997+ {
11998+ result = NI_System_Threading_Interlocked_Exchange;
11999+ }
12000+ else if (strcmp (methodName, " ExchangeAdd" ) == 0 )
12001+ {
12002+ result = NI_System_Threading_Interlocked_ExchangeAdd;
12003+ }
12004+ }
1176512005 }
1176612006 }
1176712007 }
0 commit comments