@@ -2149,14 +2149,30 @@ void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNative(ILCodeStream* ps
21492149
21502150 EmitLoadManagedValue (pslILEmit);
21512151 pslILEmit->EmitBRFALSE (pNullRefLabel);
2152+ ILCodeLabel* pTypeMismatchedLabel = pslILEmit->NewCodeLabel ();
2153+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, pTypeMismatchedLabel);
2154+ DWORD sizeLocal = pslILEmit->NewLocal (LocalDesc (ELEMENT_TYPE_I4));
2155+
21522156 pslILEmit->EmitLDC (uNativeSize);
2157+ if (emittedTypeCheck)
2158+ {
2159+ ILCodeLabel* pHaveSizeLabel = pslILEmit->NewCodeLabel ();
2160+ pslILEmit->EmitBR (pHaveSizeLabel);
2161+ pslILEmit->EmitLabel (pTypeMismatchedLabel);
2162+ EmitLoadManagedValue (pslILEmit);
2163+ pslILEmit->EmitCALL (METHOD__OBJECT__GET_TYPE, 1 , 1 );
2164+ pslILEmit->EmitCALL (METHOD__MARSHAL__SIZEOF_TYPE, 1 , 1 );
2165+ pslILEmit->EmitLabel (pHaveSizeLabel);
2166+ }
2167+ pslILEmit->EmitSTLOC (sizeLocal);
2168+ pslILEmit->EmitLDLOC (sizeLocal);
21532169 pslILEmit->EmitCALL (METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1 , 1 );
21542170 pslILEmit->EmitDUP (); // for INITBLK
21552171 EmitStoreNativeValue (pslILEmit);
21562172
21572173 // initialize local block we just allocated
21582174 pslILEmit->EmitLDC (0 );
2159- pslILEmit->EmitLDC (uNativeSize );
2175+ pslILEmit->EmitLDLOC (sizeLocal );
21602176 pslILEmit->EmitINITBLK ();
21612177
21622178 pslILEmit->EmitLabel (pNullRefLabel);
@@ -2180,15 +2196,30 @@ void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNativeTemp(ILCodeStream
21802196
21812197 EmitLoadManagedValue (pslILEmit);
21822198 pslILEmit->EmitBRFALSE (pNullRefLabel);
2199+ ILCodeLabel* pTypeMismatchedLabel = pslILEmit->NewCodeLabel ();
2200+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, pTypeMismatchedLabel);
2201+ DWORD sizeLocal = pslILEmit->NewLocal (LocalDesc (ELEMENT_TYPE_I4));
21832202
21842203 pslILEmit->EmitLDC (uNativeSize);
2204+ if (emittedTypeCheck)
2205+ {
2206+ ILCodeLabel* pHaveSizeLabel = pslILEmit->NewCodeLabel ();
2207+ pslILEmit->EmitBR (pHaveSizeLabel);
2208+ pslILEmit->EmitLabel (pTypeMismatchedLabel);
2209+ EmitLoadManagedValue (pslILEmit);
2210+ pslILEmit->EmitCALL (METHOD__OBJECT__GET_TYPE, 1 , 1 );
2211+ pslILEmit->EmitCALL (METHOD__MARSHAL__SIZEOF_TYPE, 1 , 1 );
2212+ pslILEmit->EmitLabel (pHaveSizeLabel);
2213+ }
2214+ pslILEmit->EmitSTLOC (sizeLocal);
2215+ pslILEmit->EmitLDLOC (sizeLocal);
21852216 pslILEmit->EmitLOCALLOC ();
21862217 pslILEmit->EmitDUP (); // for INITBLK
21872218 EmitStoreNativeValue (pslILEmit);
21882219
21892220 // initialize local block we just allocated
21902221 pslILEmit->EmitLDC (0 );
2191- pslILEmit->EmitLDC (uNativeSize );
2222+ pslILEmit->EmitLDLOC (sizeLocal );
21922223 pslILEmit->EmitINITBLK ();
21932224
21942225 pslILEmit->EmitLabel (pNullRefLabel);
@@ -2264,7 +2295,24 @@ void ILLayoutClassPtrMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
22642295 }
22652296}
22662297
2298+ bool ILLayoutClassPtrMarshalerBase::EmitExactTypeCheck (ILCodeStream* pslILEmit, ILCodeLabel* isNotMatchingTypeLabel)
2299+ {
2300+ STANDARD_VM_CONTRACT;
22672301
2302+ if (m_pargs->m_pMT ->IsSealed ())
2303+ {
2304+ // If the provided type cannot be derived from, then we don't need to emit the type check.
2305+ return false ;
2306+ }
2307+ EmitLoadManagedValue (pslILEmit);
2308+ pslILEmit->EmitCALL (METHOD__OBJECT__GET_TYPE, 1 , 1 );
2309+ pslILEmit->EmitLDTOKEN (pslILEmit->GetToken (m_pargs->m_pMT ));
2310+ pslILEmit->EmitCALL (METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1 , 1 );
2311+ pslILEmit->EmitCALLVIRT (pslILEmit->GetToken (CoreLibBinder::GetMethod (METHOD__OBJECT__EQUALS)), 1 , 1 );
2312+ pslILEmit->EmitBRFALSE (isNotMatchingTypeLabel);
2313+
2314+ return true ;
2315+ }
22682316
22692317void ILLayoutClassPtrMarshaler::EmitConvertContentsCLRToNative (ILCodeStream* pslILEmit)
22702318{
@@ -2281,6 +2329,9 @@ void ILLayoutClassPtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* psl
22812329 pslILEmit->EmitLDC (uNativeSize);
22822330 pslILEmit->EmitINITBLK ();
22832331
2332+ ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel ();
2333+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, isNotMatchingTypeLabel);
2334+
22842335 MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub (m_pargs->m_pMT );
22852336
22862337 EmitLoadManagedValue (pslILEmit);
@@ -2290,6 +2341,18 @@ void ILLayoutClassPtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* psl
22902341 EmitLoadCleanupWorkList (pslILEmit);
22912342
22922343 pslILEmit->EmitCALL (pslILEmit->GetToken (pStructMarshalStub), 4 , 0 );
2344+
2345+ if (emittedTypeCheck)
2346+ {
2347+ pslILEmit->EmitBR (pNullRefLabel);
2348+
2349+ pslILEmit->EmitLabel (isNotMatchingTypeLabel);
2350+ EmitLoadManagedValue (pslILEmit);
2351+ EmitLoadNativeValue (pslILEmit);
2352+ pslILEmit->EmitLDC (0 );
2353+ pslILEmit->EmitCALL (METHOD__MARSHAL__STRUCTURE_TO_PTR, 3 , 0 );
2354+ }
2355+
22932356 pslILEmit->EmitLabel (pNullRefLabel);
22942357}
22952358
@@ -2302,6 +2365,9 @@ void ILLayoutClassPtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* psl
23022365 EmitLoadManagedValue (pslILEmit);
23032366 pslILEmit->EmitBRFALSE (pNullRefLabel);
23042367
2368+ ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel ();
2369+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, isNotMatchingTypeLabel);
2370+
23052371 MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub (m_pargs->m_pMT );
23062372
23072373 EmitLoadManagedValue (pslILEmit);
@@ -2311,13 +2377,26 @@ void ILLayoutClassPtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* psl
23112377 EmitLoadCleanupWorkList (pslILEmit);
23122378
23132379 pslILEmit->EmitCALL (pslILEmit->GetToken (pStructMarshalStub), 4 , 0 );
2380+ if (emittedTypeCheck)
2381+ {
2382+ pslILEmit->EmitBR (pNullRefLabel);
2383+
2384+ pslILEmit->EmitLabel (isNotMatchingTypeLabel);
2385+ EmitLoadNativeValue (pslILEmit);
2386+ EmitLoadManagedValue (pslILEmit);
2387+ pslILEmit->EmitCALL (METHOD__MARSHAL__PTR_TO_STRUCTURE, 2 , 0 );
2388+ }
23142389 pslILEmit->EmitLabel (pNullRefLabel);
23152390}
23162391
23172392void ILLayoutClassPtrMarshaler::EmitClearNativeContents (ILCodeStream * pslILEmit)
23182393{
23192394 STANDARD_VM_CONTRACT;
23202395
2396+ ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel ();
2397+ ILCodeLabel* cleanedUpLabel = pslILEmit->NewCodeLabel ();
2398+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, isNotMatchingTypeLabel);
2399+
23212400 MethodDesc* pStructMarshalStub = NDirect::CreateStructMarshalILStub (m_pargs->m_pMT );
23222401
23232402 EmitLoadManagedValue (pslILEmit);
@@ -2327,6 +2406,19 @@ void ILLayoutClassPtrMarshaler::EmitClearNativeContents(ILCodeStream * pslILEmit
23272406 EmitLoadCleanupWorkList (pslILEmit);
23282407
23292408 pslILEmit->EmitCALL (pslILEmit->GetToken (pStructMarshalStub), 4 , 0 );
2409+
2410+ if (emittedTypeCheck)
2411+ {
2412+ pslILEmit->EmitBR (cleanedUpLabel);
2413+
2414+ pslILEmit->EmitLabel (isNotMatchingTypeLabel);
2415+ EmitLoadNativeValue (pslILEmit);
2416+ EmitLoadManagedValue (pslILEmit);
2417+ pslILEmit->EmitCALL (METHOD__OBJECT__GET_TYPE, 1 , 1 );
2418+ pslILEmit->EmitCALL (METHOD__MARSHAL__DESTROY_STRUCTURE, 2 , 0 );
2419+ }
2420+
2421+ pslILEmit->EmitLabel (cleanedUpLabel);
23302422}
23312423
23322424
@@ -2341,6 +2433,9 @@ void ILBlittablePtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslIL
23412433 EmitLoadNativeValue (pslILEmit);
23422434 pslILEmit->EmitBRFALSE (pNullRefLabel);
23432435
2436+ ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel ();
2437+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, isNotMatchingTypeLabel);
2438+
23442439 EmitLoadNativeValue (pslILEmit); // dest
23452440
23462441 EmitLoadManagedValue (pslILEmit);
@@ -2349,6 +2444,17 @@ void ILBlittablePtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslIL
23492444 pslILEmit->EmitLDC (uNativeSize); // size
23502445
23512446 pslILEmit->EmitCPBLK ();
2447+
2448+ if (emittedTypeCheck)
2449+ {
2450+ pslILEmit->EmitBR (pNullRefLabel);
2451+
2452+ pslILEmit->EmitLabel (isNotMatchingTypeLabel);
2453+ EmitLoadManagedValue (pslILEmit);
2454+ EmitLoadNativeValue (pslILEmit);
2455+ pslILEmit->EmitLDC (0 );
2456+ pslILEmit->EmitCALL (METHOD__MARSHAL__STRUCTURE_TO_PTR, 3 , 0 );
2457+ }
23522458 pslILEmit->EmitLabel (pNullRefLabel);
23532459}
23542460
@@ -2363,6 +2469,9 @@ void ILBlittablePtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslIL
23632469 EmitLoadManagedValue (pslILEmit);
23642470 pslILEmit->EmitBRFALSE (pNullRefLabel);
23652471
2472+ ILCodeLabel* isNotMatchingTypeLabel = pslILEmit->NewCodeLabel ();
2473+ bool emittedTypeCheck = EmitExactTypeCheck (pslILEmit, isNotMatchingTypeLabel);
2474+
23662475 EmitLoadManagedValue (pslILEmit);
23672476 pslILEmit->EmitLDFLDA (fieldDef); // dest
23682477
@@ -2371,12 +2480,26 @@ void ILBlittablePtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslIL
23712480 pslILEmit->EmitLDC (uNativeSize); // size
23722481
23732482 pslILEmit->EmitCPBLK ();
2483+
2484+ if (emittedTypeCheck)
2485+ {
2486+ pslILEmit->EmitBR (pNullRefLabel);
2487+
2488+ pslILEmit->EmitLabel (isNotMatchingTypeLabel);
2489+ EmitLoadNativeValue (pslILEmit);
2490+ EmitLoadManagedValue (pslILEmit);
2491+ pslILEmit->EmitCALL (METHOD__MARSHAL__PTR_TO_STRUCTURE, 2 , 0 );
2492+ }
2493+
23742494 pslILEmit->EmitLabel (pNullRefLabel);
23752495}
23762496
23772497bool ILBlittablePtrMarshaler::CanMarshalViaPinning ()
23782498{
2379- return IsCLRToNative (m_dwMarshalFlags) && !IsByref (m_dwMarshalFlags) && !IsFieldMarshal (m_dwMarshalFlags);
2499+ return IsCLRToNative (m_dwMarshalFlags) &&
2500+ !IsByref (m_dwMarshalFlags) &&
2501+ !IsFieldMarshal (m_dwMarshalFlags) &&
2502+ m_pargs->m_pMT ->IsSealed (); // We can't marshal via pinning if we might need to marshal differently at runtime. See calls to EmitExactTypeCheck where we check the runtime type of the object being marshalled.
23802503}
23812504
23822505void ILBlittablePtrMarshaler::EmitMarshalViaPinning (ILCodeStream* pslILEmit)
0 commit comments