Replace sizeof(LPVOID)==4 with #ifdef _TARGET_64BIT_ in fieldmarshaler.cpp
[platform/upstream/coreclr.git] / src / vm / fieldmarshaler.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // File: FieldMarshaler.cpp
6 //
7
8 //
9
10
11 #include "common.h"
12 #include "vars.hpp"
13 #include "class.h"
14 #include "ceeload.h"
15 #include "excep.h"
16 #include "fieldmarshaler.h"
17 #include "field.h"
18 #include "frames.h"
19 #include "dllimport.h"
20 #include "comdelegate.h"
21 #include "eeconfig.h"
22 #include "comdatetime.h"
23 #include "olevariant.h"
24 #include <cor.h>
25 #include <corpriv.h>
26 #include <corerror.h>
27 #include "sigformat.h"
28 #include "marshalnative.h"
29 #include "typeparse.h"
30 #ifdef FEATURE_COMINTEROP
31 #include <winstring.h>
32 #endif // FEATURE_COMINTEROP
33
34 // forward declaration
35 BOOL CheckForPrimitiveType(CorElementType elemType, CQuickArray<WCHAR> *pStrPrimitiveType);
36 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly);
37 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig);  
38
39
40 //=======================================================================
41 // A database of NFT types.
42 //=======================================================================
43 struct NFTDataBaseEntry
44 {
45     UINT32            m_cbNativeSize;     // native size of field (0 if not constant)
46     bool              m_fWinRTSupported;  // true if the field marshaler is supported for WinRT
47 };
48
49 static const NFTDataBaseEntry NFTDataBase[] =
50 {
51     #undef DEFINE_NFT
52     #define DEFINE_NFT(name, nativesize, fWinRTSupported) { nativesize, fWinRTSupported },
53     #include "nsenums.h"
54 };
55
56
57 //=======================================================================
58 // This is invoked from the class loader while building the internal structures for a type
59 // This function should check if explicit layout metadata exists.
60 //
61 // Returns:
62 //  TRUE    - yes, there's layout metadata
63 //  FALSE   - no, there's no layout.
64 //  fail    - throws a typeload exception
65 //
66 // If TRUE,
67 //   *pNLType            gets set to nltAnsi or nltUnicode
68 //   *pPackingSize       declared packing size
69 //   *pfExplicitoffsets  offsets explicit in metadata or computed?
70 //=======================================================================
71 BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport *pInternalImport, mdTypeDef cl, MethodTable*pParentMT, BYTE *pPackingSize, BYTE *pNLTType, BOOL *pfExplicitOffsets)
72 {
73     CONTRACTL
74     {
75         THROWS;
76         GC_TRIGGERS;
77         MODE_ANY;
78         PRECONDITION(CheckPointer(pInternalImport));
79         PRECONDITION(CheckPointer(pPackingSize));
80         PRECONDITION(CheckPointer(pNLTType));
81         PRECONDITION(CheckPointer(pfExplicitOffsets));
82     }
83     CONTRACTL_END;
84     
85     HRESULT hr;
86     ULONG clFlags;
87 #ifdef _DEBUG
88     clFlags = 0xcccccccc;
89 #endif
90     
91     if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL)))
92     {
93         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
94     }
95     
96     if (IsTdAutoLayout(clFlags))
97     {
98         // <BUGNUM>workaround for B#104780 - VC fails to set SequentialLayout on some classes
99         // with ClassSize. Too late to fix compiler for V1.
100         //
101         // To compensate, we treat AutoLayout classes as Sequential if they
102         // meet all of the following criteria:
103         //
104         //    - ClassSize present and nonzero.
105         //    - No instance fields declared
106         //    - Base class is System.ValueType.
107         //</BUGNUM>
108         ULONG cbTotalSize = 0;
109         if (SUCCEEDED(pInternalImport->GetClassTotalSize(cl, &cbTotalSize)) && cbTotalSize != 0)
110         {
111             if (pParentMT && pParentMT->IsValueTypeClass())
112             {
113                 MDEnumHolder hEnumField(pInternalImport);
114                 if (SUCCEEDED(pInternalImport->EnumInit(mdtFieldDef, cl, &hEnumField)))
115                 {
116                     ULONG numFields = pInternalImport->EnumGetCount(&hEnumField);
117                     if (numFields == 0)
118                     {
119                         *pfExplicitOffsets = FALSE;
120                         *pNLTType = nltAnsi;
121                         *pPackingSize = 1;
122                         return TRUE;
123                     }
124                 }
125             }
126         }
127         
128         return FALSE;
129     }
130     else if (IsTdSequentialLayout(clFlags))
131     {
132         *pfExplicitOffsets = FALSE;
133     }
134     else if (IsTdExplicitLayout(clFlags))
135     {
136         *pfExplicitOffsets = TRUE;
137     }
138     else
139     {
140         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
141     }
142     
143     // We now know this class has seq. or explicit layout. Ensure the parent does too.
144     if (pParentMT && !(pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass()) && !(pParentMT->HasLayout()))
145         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
146
147     if (IsTdAnsiClass(clFlags))
148     {
149         *pNLTType = nltAnsi;
150     }
151     else if (IsTdUnicodeClass(clFlags))
152     {
153         *pNLTType = nltUnicode;
154     }
155     else if (IsTdAutoClass(clFlags))
156     {
157         // We no longer support Win9x so TdAuto always maps to Unicode.
158         *pNLTType = nltUnicode;
159     }
160     else
161     {
162         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
163     }
164
165     DWORD dwPackSize;
166     hr = pInternalImport->GetClassPackSize(cl, &dwPackSize);
167     if (FAILED(hr) || dwPackSize == 0) 
168         dwPackSize = DEFAULT_PACKING_SIZE;
169
170     // This has to be reduced to a BYTE value, so we had better make sure it fits. If
171     // not, we'll throw an exception instead of trying to munge the value to what we
172     // think the user might want.
173     if (!FitsInU1((UINT64)(dwPackSize)))
174     {
175         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
176     }
177
178     *pPackingSize = (BYTE)dwPackSize;
179     
180     return TRUE;
181 }
182
183 typedef enum
184 {
185     ParseNativeTypeFlag_None    = 0x00,
186     ParseNativeTypeFlag_IsAnsi  = 0x01,
187
188 #ifdef FEATURE_COMINTEROP
189     ParseNativeTypeFlag_IsWinRT = 0x02,
190 #endif // FEATURE_COMINTEROP
191 }
192 ParseNativeTypeFlags;
193
194 inline ParseNativeTypeFlags operator|=(ParseNativeTypeFlags& lhs, ParseNativeTypeFlags rhs)
195 {
196     LIMITED_METHOD_CONTRACT;
197     lhs = static_cast<ParseNativeTypeFlags>(lhs | rhs);
198     return lhs;
199 }
200
201 #ifdef _PREFAST_
202 #pragma warning(push)
203 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
204 #endif
205 VOID ParseNativeType(Module*                     pModule,
206                          PCCOR_SIGNATURE             pCOMSignature,
207                          DWORD                       cbCOMSignature,
208                          ParseNativeTypeFlags        flags,
209                          LayoutRawFieldInfo*         pfwalk,
210                          PCCOR_SIGNATURE             pNativeType,
211                          ULONG                       cbNativeType,
212                          IMDInternalImport*          pInternalImport,
213                          mdTypeDef                   cl,
214                          const SigTypeContext *      pTypeContext,
215                          BOOL                       *pfDisqualifyFromManagedSequential  // set to TRUE if needed (never set to FALSE, it may come in as TRUE!)
216 #ifdef _DEBUG
217                          ,
218                          LPCUTF8                     szNamespace,
219                          LPCUTF8                     szClassName,
220                          LPCUTF8                     szFieldName
221 #endif
222                         )
223 {
224     CONTRACTL
225     {
226         STANDARD_VM_CHECK;
227         PRECONDITION(CheckPointer(pfwalk));
228     }
229     CONTRACTL_END;
230
231     // Make sure that there is no junk in the unused part of the field marshaler space (ngen image determinism)
232     ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
233
234 #define INITFIELDMARSHALER(nfttype, fmtype, args)       \
235 do                                                      \
236 {                                                       \
237     static_assert_no_msg(sizeof(fmtype) <= MAXFIELDMARSHALERSIZE);  \
238     pfwalk->m_nft = (nfttype);                          \
239     new ( &(pfwalk->m_FieldMarshaler) ) fmtype args;    \
240     ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->SetNStructFieldType(nfttype); \
241 } while(0)
242
243     BOOL                fAnsi               = (flags & ParseNativeTypeFlag_IsAnsi);
244 #ifdef FEATURE_COMINTEROP
245     BOOL                fIsWinRT            = (flags & ParseNativeTypeFlag_IsWinRT);
246 #endif // FEATURE_COMINTEROP
247     CorElementType      corElemType         = ELEMENT_TYPE_END;
248     PCCOR_SIGNATURE     pNativeTypeStart    = pNativeType;    
249     ULONG               cbNativeTypeStart   = cbNativeType;
250     CorNativeType       ntype;
251     BOOL                fDefault;
252     BOOL                BestFit;
253     BOOL                ThrowOnUnmappableChar;
254     
255     pfwalk->m_nft = NFT_NONE;
256
257     if (cbNativeType == 0)
258     {
259         ntype = NATIVE_TYPE_DEFAULT;
260         fDefault = TRUE;
261     }
262     else
263     {
264         ntype = (CorNativeType) *( ((BYTE*&)pNativeType)++ );
265         cbNativeType--;
266         fDefault = (ntype == NATIVE_TYPE_DEFAULT);
267     }
268
269 #ifdef FEATURE_COMINTEROP
270     if (fIsWinRT && !fDefault)
271     {
272         // Do not allow any MarshalAs in WinRT scenarios - marshaling is fully described by the field type.
273         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_MARSHAL_AS));
274     }
275 #endif // FEATURE_COMINTEROP
276
277     // Setup the signature and normalize
278     MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField);
279     corElemType = fsig.NextArgNormalized();
280
281
282     if (!(*pfDisqualifyFromManagedSequential))
283     {
284         // This type may qualify for ManagedSequential. Collect managed size and alignment info.
285         if (CorTypeInfo::IsPrimitiveType(corElemType))
286         {
287             pfwalk->m_managedSize = ((UINT32)CorTypeInfo::Size(corElemType)); // Safe cast - no primitive type is larger than 4gb!
288             pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
289         }
290         else if (corElemType == ELEMENT_TYPE_PTR)
291         {
292             pfwalk->m_managedSize = TARGET_POINTER_SIZE;
293             pfwalk->m_managedAlignmentReq = TARGET_POINTER_SIZE;
294         }
295         else if (corElemType == ELEMENT_TYPE_VALUETYPE)
296         {
297             TypeHandle pNestedType = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
298                                                                     CLASS_LOAD_APPROXPARENTS,
299                                                                     TRUE);
300             if (pNestedType.GetMethodTable()->IsManagedSequential())
301             {
302                 pfwalk->m_managedSize = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes());
303
304                 _ASSERTE(pNestedType.GetMethodTable()->HasLayout()); // If it is ManagedSequential(), it also has Layout but doesn't hurt to check before we do a cast!
305                 pfwalk->m_managedAlignmentReq = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers;
306             }
307             else
308             {
309                 *pfDisqualifyFromManagedSequential = TRUE;
310             }
311         }
312         else
313         {
314             // No other type permitted for ManagedSequential.
315             *pfDisqualifyFromManagedSequential = TRUE;
316         }
317     }
318
319 #ifdef _TARGET_X86_
320     // Normalization might have put corElementType and ntype out of sync which can
321     // result in problems with non-default ntype being validated against the 
322     // normalized primitive corElemType.
323     //
324     VerifyAndAdjustNormalizedType(pModule, fsig.GetArgProps(), fsig.GetSigTypeContext(), &corElemType, &ntype);
325
326     fDefault = (ntype == NATIVE_TYPE_DEFAULT);
327 #endif // _TARGET_X86_
328
329     CorElementType sigElemType;
330     IfFailThrow(fsig.GetArgProps().PeekElemType(&sigElemType));
331     if ((sigElemType == ELEMENT_TYPE_GENERICINST || sigElemType == ELEMENT_TYPE_VAR) && corElemType == ELEMENT_TYPE_CLASS)
332     {
333         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_GENERICS_RESTRICTION));
334     }
335     else switch (corElemType)
336     {
337         case ELEMENT_TYPE_CHAR:
338             if (fDefault)
339             {
340                 if (fAnsi)
341                 {
342                     ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
343                     INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
344                 }
345                 else
346                 {
347                     INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
348                 }
349             }
350             else if (ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
351             {
352                 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
353                 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
354             }
355             else if (ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
356             {
357                 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
358             }
359             else
360             {
361                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CHAR));
362             }
363             break;
364
365         case ELEMENT_TYPE_BOOLEAN:
366             if (fDefault)
367             {
368 #ifdef FEATURE_COMINTEROP
369                 if (fIsWinRT)
370                 {
371                     INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
372                 }
373                 else
374 #endif // FEATURE_COMINTEROP
375                 {
376                     INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
377                 }
378             }
379             else if (ntype == NATIVE_TYPE_BOOLEAN)
380             {
381                 INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
382             }
383 #ifdef FEATURE_COMINTEROP
384             else if (ntype == NATIVE_TYPE_VARIANTBOOL)
385             {
386                 INITFIELDMARSHALER(NFT_VARIANTBOOL, FieldMarshaler_VariantBool, ());
387             }
388 #endif // FEATURE_COMINTEROP
389             else if (ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
390             {
391                 INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
392             }
393             else
394             {
395                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BOOLEAN));
396             }
397             break;
398
399
400         case ELEMENT_TYPE_I1:
401             if (fDefault || ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
402             {
403                 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
404             }
405             else
406             {
407                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
408             }
409             break;
410
411         case ELEMENT_TYPE_U1:
412             if (fDefault || ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
413             {
414                 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
415             }
416             else
417             {
418                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
419             }
420             break;
421
422         case ELEMENT_TYPE_I2:
423             if (fDefault || ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
424             {
425                 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
426             }
427             else
428             {
429                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
430             }
431             break;
432
433         case ELEMENT_TYPE_U2:
434             if (fDefault || ntype == NATIVE_TYPE_U2 || ntype == NATIVE_TYPE_I2)
435             {
436                 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
437             }
438             else
439             {
440                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
441             }
442             break;
443
444         case ELEMENT_TYPE_I4:
445             if (fDefault || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_ERROR)
446             {
447                 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
448             }
449             else
450             {
451                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
452             }
453             break;
454             
455         case ELEMENT_TYPE_U4:
456             if (fDefault || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_ERROR)
457             {
458                 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
459             }
460             else
461             {
462                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
463             }
464             break;
465
466         case ELEMENT_TYPE_I8:
467             if (fDefault || ntype == NATIVE_TYPE_I8 || ntype == NATIVE_TYPE_U8)
468             {
469                 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
470             }
471             else
472             {
473                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
474             }
475             break;
476
477         case ELEMENT_TYPE_U8:
478             if (fDefault || ntype == NATIVE_TYPE_U8 || ntype == NATIVE_TYPE_I8)
479             {
480                 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
481             }
482             else
483             {
484                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
485             }
486             break;
487
488         case ELEMENT_TYPE_I: //fallthru
489         case ELEMENT_TYPE_U:
490 #ifdef FEATURE_COMINTEROP
491             if (fIsWinRT)
492             {
493                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
494             }
495             else
496 #endif // FEATURE_COMINTEROP
497             if (fDefault || ntype == NATIVE_TYPE_INT || ntype == NATIVE_TYPE_UINT)
498             {
499 #ifdef _TARGET_64BIT_
500                 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
501 #else // !_TARGET_64BIT_
502                 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
503 #endif // !_TARGET_64BIT_
504             }
505             else
506             {
507                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I));
508             }
509             break;
510
511         case ELEMENT_TYPE_R4:
512             if (fDefault || ntype == NATIVE_TYPE_R4)
513             {
514                 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
515             }
516             else
517             {
518                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R4));
519             }
520             break;
521             
522         case ELEMENT_TYPE_R8:
523             if (fDefault || ntype == NATIVE_TYPE_R8)
524             {
525                 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
526             }
527             else
528             {
529                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R8));
530             }
531             break;
532
533         case ELEMENT_TYPE_PTR:
534 #ifdef FEATURE_COMINTEROP
535             if (fIsWinRT)
536             {
537                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
538             }
539             else
540 #endif // FEATURE_COMINTEROP
541             if (fDefault)
542             {
543 #ifdef _TARGET_64BIT_
544                 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
545 #else // !_TARGET_64BIT_
546                 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
547 #endif // !_TARGET_64BIT_
548             }
549             else
550             {
551                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_PTR));
552             }
553             break;
554
555         case ELEMENT_TYPE_VALUETYPE:
556         {
557             // This may cause a TypeLoadException, which we currently seem to have to swallow.
558             // This happens with structs that contain fields of class type where the class itself
559             // refers to the struct in a field.
560             TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
561             if (!thNestedType.GetMethodTable())
562                 break;
563 #ifdef FEATURE_COMINTEROP
564             if (fIsWinRT && sigElemType == ELEMENT_TYPE_GENERICINST)
565             {
566                 // If this is a generic value type, lets see whether it is a Nullable<T>
567                 TypeHandle genType = fsig.GetLastTypeHandleThrowing();
568                 if(genType != NULL && genType.GetMethodTable()->HasSameTypeDefAs(g_pNullableClass))
569                 {
570                     // The generic type is System.Nullable<T>. 
571                     // Lets extract the typeArg and check if the typeArg is valid.
572                     // typeArg is invalid if
573                     // 1. It is not a value type.
574                     // 2. It is string
575                     // 3. We have an open type with us.
576                     Instantiation inst = genType.GetMethodTable()->GetInstantiation();
577                     MethodTable* typeArgMT = inst[0].GetMethodTable();
578                     if (!typeArgMT->IsLegalNonArrayWinRTType())
579                     {
580                         // Type is not a valid WinRT value type.
581                         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NULLABLE_RESTRICTION));
582                     }
583                     else
584                     {
585                         INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONIREFERENCE, FieldMarshaler_Nullable, (genType.GetMethodTable()));
586                     }
587                     break;
588                 }
589             }
590 #endif
591            if (fsig.IsClass(g_DateClassName))
592             {
593                 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
594                 {
595                     INITFIELDMARSHALER(NFT_DATE, FieldMarshaler_Date, ());
596                 }
597                 else
598                 {
599                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIME));
600                 }
601             }
602             else if (fsig.IsClass(g_DecimalClassName))
603             {
604                 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
605                 {
606                     INITFIELDMARSHALER(NFT_DECIMAL, FieldMarshaler_Decimal, ());
607                 }
608 #ifdef FEATURE_COMINTEROP
609                 else if (ntype == NATIVE_TYPE_CURRENCY)
610                 {
611                     INITFIELDMARSHALER(NFT_CURRENCY, FieldMarshaler_Currency, ());
612                 }
613 #endif // FEATURE_COMINTEROP
614                 else
615                 {
616                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_DECIMAL));                    
617                 }
618             }
619 #ifdef FEATURE_COMINTEROP
620             else if (fsig.IsClass(g_DateTimeOffsetClassName))
621             {
622                 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
623                 {
624                     INITFIELDMARSHALER(NFT_DATETIMEOFFSET, FieldMarshaler_DateTimeOffset, ());
625                 }
626                 else
627                 {
628                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIMEOFFSET));
629                 }
630             }
631             else if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
632             {
633                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
634             }
635 #endif // FEATURE_COMINTEROP
636             else if (thNestedType.GetMethodTable()->HasLayout())
637             {
638                 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
639                 {
640                     if (IsStructMarshalable(thNestedType))
641                     {
642                         INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable()));
643                     }
644                     else
645                     {
646                         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
647                     }
648                 }
649                 else
650                 {
651                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_VALUETYPE));                                        
652                 }
653             }
654             else
655             {
656                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
657             }
658             break;
659         }
660
661         case ELEMENT_TYPE_CLASS:
662         {
663             // This may cause a TypeLoadException, which we currently seem to have to swallow.
664             // This happens with structs that contain fields of class type where the class itself
665             // refers to the struct in a field.
666             TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
667             if (!thNestedType.GetMethodTable())
668                 break;
669                        
670             if (thNestedType.GetMethodTable()->IsObjectClass())
671             {
672 #ifdef FEATURE_COMINTEROP                
673                 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
674                 {
675                     // Only NATIVE_TYPE_IDISPATCH maps to an IDispatch based interface pointer.
676                     DWORD dwFlags = ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF;
677                     if (ntype == NATIVE_TYPE_IDISPATCH)
678                     {
679                         dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
680                     }
681                     INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (NULL, NULL, dwFlags));
682                 }
683                 else if (ntype == NATIVE_TYPE_STRUCT)
684                 {
685                     INITFIELDMARSHALER(NFT_VARIANT, FieldMarshaler_Variant, ());
686                 }
687 #else // FEATURE_COMINTEROP
688                 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
689                 {
690                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
691                 }
692                 else if (ntype == NATIVE_TYPE_STRUCT)
693                 {
694                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED));
695                 }
696 #endif // FEATURE_COMINTEROP
697                 else
698                 {
699                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_OBJECT));
700                 }
701             }
702 #ifdef FEATURE_COMINTEROP                
703             else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
704             {
705                 if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
706                 {
707                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
708                 }
709                 else
710                 {
711                     ItfMarshalInfo itfInfo;
712                     if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
713                         break;
714
715                     INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
716                 }
717             }
718 #else  // FEATURE_COMINTEROP
719             else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
720             {
721                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
722             }
723 #endif // FEATURE_COMINTEROP
724             else if (ntype == NATIVE_TYPE_CUSTOMMARSHALER)
725             {
726                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH));
727             }
728             else if (thNestedType == TypeHandle(g_pStringClass))
729             {
730                 if (fDefault)
731                 {
732 #ifdef FEATURE_COMINTEROP
733                     if (fIsWinRT)
734                     {
735                         INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
736                     }
737                     else
738 #endif // FEATURE_COMINTEROP
739                     if (fAnsi)
740                     {
741                         ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
742                         INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
743                     }
744                     else
745                     {
746                         INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
747                     }
748                 }
749                 else
750                 {
751                     switch (ntype)
752                     {
753                         case NATIVE_TYPE_LPSTR:
754                             ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
755                             INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
756                             break;
757
758                         case NATIVE_TYPE_LPWSTR:
759                             INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
760                             break;
761                         
762                         case NATIVE_TYPE_LPUTF8STR:
763                                                         INITFIELDMARSHALER(NFT_STRINGUTF8, FieldMarshaler_StringUtf8, ());
764                                                         break;
765
766                         case NATIVE_TYPE_LPTSTR:
767                             // We no longer support Win9x so LPTSTR always maps to a Unicode string.
768                             INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
769                             break;
770 #ifdef FEATURE_COMINTEROP
771                         case NATIVE_TYPE_BSTR:
772                             INITFIELDMARSHALER(NFT_BSTR, FieldMarshaler_BSTR, ());
773                             break;
774
775                         case NATIVE_TYPE_HSTRING:
776                             INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
777                             break;
778 #endif // FEATURE_COMINTEROP
779                         case NATIVE_TYPE_FIXEDSYSSTRING:
780                             {
781                                 ULONG nchars;
782                                 ULONG udatasize = CorSigUncompressedDataSize(pNativeType);
783
784                                 if (cbNativeType < udatasize)
785                                     break;
786
787                                 nchars = CorSigUncompressData(pNativeType);
788                                 cbNativeType -= udatasize;
789
790                                 if (nchars == 0)
791                                 {
792                                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING));
793                                     break;  
794                                 }
795
796                                 if (fAnsi)
797                                 {
798                                     ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
799                                     INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar));
800                                 }
801                                 else
802                                 {
803                                     INITFIELDMARSHALER(NFT_FIXEDSTRINGUNI, FieldMarshaler_FixedStringUni, (nchars));
804                                 }
805                             }
806                         break;
807
808                         default:
809                             INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_STRING));
810                             break;
811                     }
812                 }
813             }
814 #ifdef FEATURE_COMINTEROP
815             else if (fIsWinRT && fsig.IsClass(g_TypeClassName))
816             {   // Note: If the System.Type field is in non-WinRT struct, do not change the previously shipped behavior
817                 INITFIELDMARSHALER(NFT_SYSTEMTYPE, FieldMarshaler_SystemType, ());
818             }
819             else if (fIsWinRT && fsig.IsClass(g_ExceptionClassName))  // Marshal Windows.Foundation.HResult as System.Exception for WinRT.
820             {
821                 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONHRESULT, FieldMarshaler_Exception, ());
822             }
823 #endif //FEATURE_COMINTEROP
824 #ifdef FEATURE_CLASSIC_COMINTEROP
825             else if (thNestedType.GetMethodTable() == g_pArrayClass)
826             {
827                 if (ntype == NATIVE_TYPE_SAFEARRAY)
828                 {
829                     NativeTypeParamInfo ParamInfo;
830                     CorElementType etyp = ELEMENT_TYPE_OBJECT;
831                     MethodTable* pMT = NULL;
832                     VARTYPE vtElement = VT_EMPTY;
833
834                     // Compat: If no safe array used def subtype was specified, we assume TypeOf(Object).                            
835                     TypeHandle thElement = TypeHandle(g_pObjectClass);
836
837                     // If we have no native type data, assume default behavior
838                     if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
839                     {
840                         INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (VT_EMPTY, NULL));
841                         break;
842                     }
843       
844                     vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
845
846                     // Extract the name of the record type's.
847                     if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
848                     {
849                         ULONG strLen;
850                         if (FAILED(CPackedLen::SafeGetData(pNativeType, pNativeTypeStart + cbNativeTypeStart, &strLen, &pNativeType)))
851                         {
852                             INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMETADATA)); 
853                             break;
854                         }
855                         if (strLen > 0)
856                         {
857                             // Load the type. Use a SString for the string since we need to NULL terminate the string
858                             // that comes from the metadata.
859                             StackSString safeArrayUserDefTypeName(SString::Utf8, (LPCUTF8)pNativeType, strLen);
860                             _ASSERTE((ULONG)(pNativeType + strLen - pNativeTypeStart) == cbNativeTypeStart);
861
862                             // Sadly this may cause a TypeLoadException, which we currently have to swallow.
863                             // This happens with structs that contain fields of class type where the class itself
864                             // refers to the struct in a field.
865                             thElement = ArraySubTypeLoadWorker(safeArrayUserDefTypeName, pModule->GetAssembly());
866                             if (thElement.IsNull())
867                                 break;
868                         }                           
869                     }
870
871                     ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
872                     arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
873
874                     if (!arrayMarshalInfo.IsValid())
875                     {
876                         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); 
877                         break;
878                     }
879
880                     INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
881                 }
882                 else if (ntype == NATIVE_TYPE_FIXEDARRAY)
883                 {
884                     // Check for the number of elements. This is required, if not present fail.
885                     if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
886                     {
887                         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));                            
888                         break;
889                     }
890                             
891                     ULONG numElements = CorSigUncompressData(/*modifies*/pNativeType);
892
893                     if (numElements == 0)
894                     {
895                         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));                            
896                         break;
897                     }
898                            
899                     // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
900
901                     // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
902                     INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, VT_BSTR, g_pStringClass));
903                 }
904             }
905 #endif // FEATURE_CLASSIC_COMINTEROP
906             else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable()))
907             {
908                 if (fDefault || ntype == NATIVE_TYPE_FUNC)
909                 {
910                     INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable()));
911                 }
912                 else
913                 {
914                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE));
915                 }
916             } 
917             else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
918             {
919                 if (fDefault) 
920                 {
921                     INITFIELDMARSHALER(NFT_SAFEHANDLE, FieldMarshaler_SafeHandle, ());
922                 }
923                 else 
924                 {
925                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_SAFEHANDLE));
926                 }
927             }
928             else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
929             {
930                 if (fDefault) 
931                 {
932                     INITFIELDMARSHALER(NFT_CRITICALHANDLE, FieldMarshaler_CriticalHandle, ());
933                 }
934                 else 
935                 {
936                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CRITICALHANDLE));
937                 }
938             }
939             else if (fsig.IsClass(g_StringBufferClassName))
940             {
941                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER));
942             }
943             else if (IsStructMarshalable(thNestedType))
944             {
945                 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
946                 {
947                     INITFIELDMARSHALER(NFT_NESTEDLAYOUTCLASS, FieldMarshaler_NestedLayoutClass, (thNestedType.GetMethodTable()));
948                 }
949                 else
950                 {
951                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_LAYOUTCLASS));
952                 }
953             }
954 #ifdef FEATURE_COMINTEROP
955             else if (fIsWinRT)
956             {
957                 // no other reference types are allowed as field types in WinRT
958                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
959             }
960             else if (fDefault)
961             {
962                 ItfMarshalInfo itfInfo;
963                 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
964                 {
965                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
966                 }
967                 else
968                 {
969                     INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
970                 }
971             }
972 #endif  // FEATURE_COMINTEROP
973             break;
974         }
975
976         case ELEMENT_TYPE_SZARRAY:
977         case ELEMENT_TYPE_ARRAY:
978         {
979 #ifdef FEATURE_COMINTEROP
980             if (fIsWinRT)
981             {
982                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
983                 break;
984             }
985 #endif // FEATURE_COMINTEROP
986
987             // This may cause a TypeLoadException, which we currently seem to have to swallow.
988             // This happens with structs that contain fields of class type where the class itself
989             // refers to the struct in a field.
990             TypeHandle thArray = GetFieldTypeHandleWorker(&fsig);
991             if (thArray.IsNull() || !thArray.IsArray())
992                 break;
993
994             TypeHandle thElement = thArray.AsArray()->GetArrayElementTypeHandle();
995             if (thElement.IsNull())
996                 break;
997
998             if (ntype == NATIVE_TYPE_FIXEDARRAY)
999             {
1000                 CorNativeType elementNativeType = NATIVE_TYPE_DEFAULT;
1001                 
1002                 // The size constant must be specified, if it isn't then the struct can't be marshalled.
1003                 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1004                 {
1005                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));                            
1006                     break;
1007                 }
1008
1009                 // Read the size const, if it's 0, then the struct can't be marshalled.
1010                 ULONG numElements = CorSigUncompressData(pNativeType);            
1011                 if (numElements == 0)
1012                 {
1013                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));                            
1014                     break;
1015                 }
1016
1017                 // The array sub type is optional so extract it if specified.
1018                 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1019                     elementNativeType = (CorNativeType)CorSigUncompressData(pNativeType);
1020
1021                 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1022                 arrayMarshalInfo.InitForFixedArray(thElement, elementNativeType, fAnsi);
1023
1024                 if (!arrayMarshalInfo.IsValid())
1025                 {
1026                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); 
1027                     break;
1028                 }
1029
1030                 if (arrayMarshalInfo.GetElementVT() == VTHACK_ANSICHAR)
1031                 {
1032                     // We need to special case fixed sized arrays of ANSI chars since the OleVariant code
1033                     // that is used by the generic fixed size array marshaller doesn't support them
1034                     // properly. 
1035                     ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
1036                     INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar));
1037                     break;                    
1038                 }
1039                 else
1040                 {
1041                     VARTYPE elementVT = arrayMarshalInfo.GetElementVT();
1042
1043                     INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1044                     break;
1045                 }
1046             }
1047 #ifdef FEATURE_CLASSIC_COMINTEROP
1048             else if (fDefault || ntype == NATIVE_TYPE_SAFEARRAY)
1049             {
1050                 VARTYPE vtElement = VT_EMPTY;
1051
1052                 // Check for data remaining in the signature before we attempt to grab some.
1053                 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1054                     vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
1055
1056                 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1057                 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
1058
1059                 if (!arrayMarshalInfo.IsValid())
1060                 {
1061                     INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); 
1062                     break;
1063                 }
1064                     
1065                 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1066             }
1067 #endif //FEATURE_CLASSIC_COMINTEROP
1068             else
1069             {
1070                 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ARRAY));                     
1071             }
1072             break;
1073         }            
1074
1075         case ELEMENT_TYPE_OBJECT:
1076         case ELEMENT_TYPE_STRING:
1077             break;
1078
1079         default:
1080             // let it fall thru as NFT_NONE
1081             break;
1082     }
1083
1084     if (pfwalk->m_nft == NFT_NONE)
1085     {
1086         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
1087     }
1088 #ifdef FEATURE_COMINTEROP
1089     else if (fIsWinRT && !NFTDataBase[pfwalk->m_nft].m_fWinRTSupported)
1090     {
1091         // the field marshaler we came up with is not supported in WinRT scenarios
1092         ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
1093         INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
1094     }
1095 #endif // FEATURE_COMINTEROP
1096 #undef INITFIELDMARSHALER
1097 }
1098 #ifdef _PREFAST_
1099 #pragma warning(pop)
1100 #endif
1101
1102
1103 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly)
1104 {
1105     CONTRACTL
1106     {
1107         THROWS;
1108         GC_TRIGGERS;
1109         MODE_ANY;
1110         PRECONDITION(CheckPointer(pAssembly));
1111     }
1112     CONTRACTL_END;
1113     
1114     TypeHandle th; 
1115
1116     EX_TRY
1117     {
1118         // Load the user defined type.
1119         StackScratchBuffer utf8Name;
1120         th = TypeName::GetTypeUsingCASearchRules(strUserDefTypeName.GetUTF8(utf8Name), pAssembly);
1121     }
1122     EX_CATCH
1123     {
1124     }
1125     EX_END_CATCH(RethrowTerminalExceptions)
1126     
1127     return th;
1128 }
1129
1130
1131 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig)
1132 {
1133     CONTRACTL
1134     {
1135         THROWS;
1136         GC_TRIGGERS;
1137         MODE_ANY;
1138         PRECONDITION(CheckPointer(pFieldSig));
1139     }
1140     CONTRACTL_END;
1141
1142     TypeHandle th; 
1143
1144     EX_TRY
1145     {
1146         // Load the user defined type.
1147         th = pFieldSig->GetLastTypeHandleThrowing(ClassLoader::LoadTypes, 
1148                                                   CLASS_LOAD_APPROXPARENTS,
1149                                                   TRUE /*dropGenericArgumentLevel*/);
1150     }
1151     EX_CATCH
1152     {
1153     }
1154     EX_END_CATCH(RethrowTerminalExceptions)
1155
1156     return th;
1157 }
1158
1159
1160 //=======================================================================
1161 // This function returns TRUE if the type passed in is either a value class or a class and if it has layout information 
1162 // and is marshalable. In all other cases it will return FALSE. 
1163 //=======================================================================
1164 BOOL IsStructMarshalable(TypeHandle th)
1165 {
1166     CONTRACTL
1167     {
1168         NOTHROW;
1169         GC_NOTRIGGER;
1170         MODE_ANY;
1171         SO_TOLERANT;
1172         PRECONDITION(!th.IsNull());
1173     }
1174     CONTRACTL_END;
1175     
1176     if (th.IsBlittable())
1177     {
1178         // th.IsBlittable will return true for arrays of blittable types, however since IsStructMarshalable
1179         // is only supposed to return true for value classes or classes with layout that are marshallable
1180         // we need to return false if the type is an array.
1181         if (th.IsArray())
1182             return FALSE;
1183         else
1184             return TRUE;
1185     }
1186
1187     // Check to see if the type has layout.
1188     if (!th.HasLayout())
1189         return FALSE;
1190
1191     MethodTable *pMT= th.GetMethodTable();
1192     PREFIX_ASSUME(pMT != NULL);
1193     
1194     if (pMT->IsStructMarshalable())
1195         return TRUE;
1196
1197     const FieldMarshaler *pFieldMarshaler = pMT->GetLayoutInfo()->GetFieldMarshalers();
1198     UINT  numReferenceFields              = pMT->GetLayoutInfo()->GetNumCTMFields();
1199
1200     while (numReferenceFields--)
1201     {
1202         if (pFieldMarshaler->GetNStructFieldType() == NFT_ILLEGAL)
1203             return FALSE;
1204
1205         ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1206     }
1207
1208     return TRUE;
1209 }
1210
1211
1212 //=======================================================================
1213 // Called from the clsloader to load up and summarize the field metadata
1214 // for layout classes.
1215 //
1216 // Warning: This function can load other classes (esp. for nested structs.)
1217 //=======================================================================
1218 #ifdef _PREFAST_
1219 #pragma warning(push)
1220 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1221 #endif
1222 VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
1223    mdTypeDef      cl,               // cl of the NStruct being loaded
1224    BYTE           packingSize,      // packing size (from @dll.struct)
1225    BYTE           nlType,           // nltype (from @dll.struct)
1226 #ifdef FEATURE_COMINTEROP
1227    BOOL           isWinRT,          // Is the type a WinRT type
1228 #endif // FEATURE_COMINTEROP
1229    BOOL           fExplicitOffsets, // explicit offsets?
1230    MethodTable   *pParentMT,        // the loaded superclass
1231    ULONG          cMembers,         // total number of members (methods + fields)
1232    HENUMInternal *phEnumField,      // enumerator for field
1233    Module        *pModule,          // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
1234    const SigTypeContext *pTypeContext,          // Type parameters for NStruct being loaded
1235    EEClassLayoutInfo    *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
1236    LayoutRawFieldInfo   *pInfoArrayOut,         // caller-allocated array to fill in.  Needs room for cMember+1 elements
1237    LoaderAllocator      *pAllocator,
1238    AllocMemTracker      *pamTracker
1239 )
1240 {
1241     CONTRACTL
1242     {
1243         THROWS;
1244         GC_TRIGGERS;
1245         MODE_ANY;
1246         INJECT_FAULT(COMPlusThrowOM());
1247         PRECONDITION(CheckPointer(pModule));
1248     }
1249     CONTRACTL_END;
1250
1251     HRESULT             hr;
1252     MD_CLASS_LAYOUT     classlayout;
1253     mdFieldDef          fd;
1254     ULONG               ulOffset;
1255     ULONG cFields = 0;
1256
1257     // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
1258     // function exits.
1259     BOOL                fDisqualifyFromManagedSequential = FALSE; 
1260
1261     // Internal interface for the NStruct being loaded.
1262     IMDInternalImport *pInternalImport = pModule->GetMDImport();
1263
1264
1265 #ifdef _DEBUG
1266     LPCUTF8 szName; 
1267     LPCUTF8 szNamespace; 
1268     if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
1269     {
1270         szName = szNamespace = "Invalid TypeDef record";
1271     }
1272     
1273     if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
1274         CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
1275 #endif
1276
1277
1278     // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
1279     // ManagedSequential. Other issues checked below might also disqualify the type.
1280     if ( (!fExplicitOffsets) &&    // Is it marked sequential?
1281          (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential()))  // Is it a valuetype or derived from a qualifying valuetype?
1282        )
1283     {
1284         // Type qualifies so far... need do nothing.
1285     }
1286     else
1287     {
1288         fDisqualifyFromManagedSequential = TRUE;
1289     }
1290
1291
1292     BOOL fHasNonTrivialParent = pParentMT &&
1293                                 !pParentMT->IsObjectClass() &&
1294                                 !pParentMT->IsValueTypeClass();
1295
1296
1297     //====================================================================
1298     // First, some validation checks.
1299     //====================================================================
1300     _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
1301
1302     hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
1303     if (FAILED(hr))
1304     {
1305         COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
1306     }
1307
1308     pEEClassLayoutInfoOut->m_numCTMFields        = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
1309     pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
1310     pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
1311     if (fHasNonTrivialParent)
1312         pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
1313     pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);    
1314     pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
1315     pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
1316
1317     LayoutRawFieldInfo *pfwalk = pInfoArrayOut;
1318     
1319     S_UINT32 cbSortArraySize = S_UINT32(cMembers) * S_UINT32(sizeof(LayoutRawFieldInfo *));
1320     if (cbSortArraySize.IsOverflow())
1321     {
1322         ThrowHR(COR_E_TYPELOAD);
1323     }
1324     LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value());
1325     LayoutRawFieldInfo **pSortArrayEnd = pSortArray;
1326     
1327     ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
1328     
1329     
1330     //=====================================================================
1331     // Phase 1: Figure out the NFT of each field based on both the CLR
1332     // signature of the field and the FieldMarshaler metadata. 
1333     //=====================================================================
1334     BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
1335     UINT32 cbAdjustedParentLayoutNativeSize = 0;
1336     EEClassLayoutInfo *pParentLayoutInfo = NULL;;
1337     if (fParentHasLayout)
1338     {
1339         pParentLayoutInfo = pParentMT->GetLayoutInfo();
1340         // Treat base class as an initial member.
1341         cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
1342         // If the parent was originally a zero-sized explicit type but
1343         // got bumped up to a size of 1 for compatibility reasons, then
1344         // we need to remove the padding, but ONLY for inheritance situations.
1345         if (pParentLayoutInfo->IsZeroSized()) {
1346             CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
1347             cbAdjustedParentLayoutNativeSize = 0;
1348         }
1349     }
1350
1351     ULONG i;
1352     for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
1353     {
1354         DWORD dwFieldAttrs;
1355         ULONG rid = RidFromToken(fd);
1356
1357         if((rid == 0)||(rid > maxRid))
1358         {
1359             COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
1360         }
1361
1362         IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
1363         
1364         PCCOR_SIGNATURE pNativeType = NULL;
1365         ULONG cbNativeType;
1366         // We ignore marshaling data attached to statics and literals,
1367         // since these do not contribute to instance data.
1368         if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
1369         {
1370             PCCOR_SIGNATURE pCOMSignature;
1371             ULONG       cbCOMSignature;
1372
1373             if (IsFdHasFieldMarshal(dwFieldAttrs))
1374             {
1375                 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
1376                 if (FAILED(hr))
1377                     cbNativeType = 0;
1378             }
1379             else
1380                 cbNativeType = 0;
1381             
1382             IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature));
1383             
1384             IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport));
1385             
1386             // fill the appropriate entry in pInfoArrayOut
1387             pfwalk->m_MD = fd;
1388             pfwalk->m_nft = NULL;
1389             pfwalk->m_offset = (UINT32) -1;
1390             pfwalk->m_sequence = 0;
1391
1392 #ifdef _DEBUG
1393             LPCUTF8 szFieldName;
1394             if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
1395             {
1396                 szFieldName = "Invalid FieldDef record";
1397             }
1398 #endif
1399
1400             ParseNativeTypeFlags flags = ParseNativeTypeFlag_None;
1401 #ifdef FEATURE_COMINTEROP
1402             if (isWinRT)
1403                 flags |= ParseNativeTypeFlag_IsWinRT;
1404             else // WinRT types have nlType == nltAnsi but should be treated as Unicode
1405 #endif // FEATURE_COMINTEROP
1406             if (nlType == nltAnsi)
1407                 flags |=  ParseNativeTypeFlag_IsAnsi;
1408
1409             ParseNativeType(pModule,
1410                             pCOMSignature,
1411                             cbCOMSignature,
1412                             flags,
1413                             pfwalk,
1414                             pNativeType,
1415                             cbNativeType,
1416                             pInternalImport,
1417                             cl,
1418                             pTypeContext,
1419                             &fDisqualifyFromManagedSequential
1420 #ifdef _DEBUG
1421                             ,
1422                             szNamespace,
1423                             szName,
1424                             szFieldName
1425 #endif
1426                                 );
1427
1428
1429             //<TODO>@nice: This is obviously not the place to bury this logic.
1430             // We're replacing NFT's with MARSHAL_TYPES_* in the near future
1431             // so this isn't worth perfecting.</TODO>
1432
1433             BOOL    resetBlittable = TRUE;
1434
1435             // if it's a simple copy...
1436             if (pfwalk->m_nft == NFT_COPY1    ||
1437                 pfwalk->m_nft == NFT_COPY2    ||
1438                 pfwalk->m_nft == NFT_COPY4    ||
1439                 pfwalk->m_nft == NFT_COPY8)
1440             {
1441                 resetBlittable = FALSE;
1442             }
1443
1444             // Or if it's a nested value class that is itself blittable...
1445             if (pfwalk->m_nft == NFT_NESTEDVALUECLASS)
1446             {
1447                 FieldMarshaler *pFM = (FieldMarshaler*)&(pfwalk->m_FieldMarshaler);
1448                 _ASSERTE(pFM->IsNestedValueClassMarshaler());
1449
1450                 if (((FieldMarshaler_NestedValueClass *) pFM)->IsBlittable())
1451                     resetBlittable = FALSE;
1452             }
1453
1454             // ...Otherwise, this field prevents blitting
1455             if (resetBlittable)
1456                 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
1457
1458             cFields++;
1459             pfwalk++;
1460         }
1461     }
1462
1463     _ASSERTE(i == cMembers);
1464
1465     // NULL out the last entry
1466     pfwalk->m_MD = mdFieldDefNil;
1467     
1468     
1469     //
1470     // fill in the layout information 
1471     //
1472     
1473     // pfwalk points to the beginging of the array
1474     pfwalk = pInfoArrayOut;
1475
1476     while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
1477                                      &classlayout,
1478                                      &fd,
1479                                      &ulOffset)) &&
1480                                      fd != mdFieldDefNil)
1481     {
1482         // watch for the last entry: must be mdFieldDefNil
1483         while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd))
1484             pfwalk++;
1485
1486         // if we haven't found a matching token, it must be a static field with layout -- ignore it
1487         if(pfwalk->m_MD != fd) continue;
1488
1489         if (!fExplicitOffsets)
1490         {
1491             // ulOffset is the sequence
1492             pfwalk->m_sequence = ulOffset;
1493         }
1494         else
1495         {
1496             // ulOffset is the explicit offset
1497             pfwalk->m_offset = ulOffset;
1498             pfwalk->m_sequence = (ULONG) -1;
1499
1500             // Treat base class as an initial member.
1501             if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize))
1502                 COMPlusThrowOM();
1503         }
1504     }
1505     IfFailThrow(hr);
1506
1507     // now sort the array
1508     if (!fExplicitOffsets)
1509     { 
1510         // sort sequential by ascending sequence
1511         for (i = 0; i < cFields; i++)
1512         {
1513             LayoutRawFieldInfo**pSortWalk = pSortArrayEnd;
1514             while (pSortWalk != pSortArray)
1515             {
1516                 if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence)
1517                     break;
1518
1519                 pSortWalk--;
1520             }
1521
1522             // pSortWalk now points to the target location for new FieldInfo.
1523             MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
1524             *pSortWalk = &pInfoArrayOut[i];
1525             pSortArrayEnd++;
1526         }
1527     }
1528     else // no sorting for explicit layout
1529     {
1530         for (i = 0; i < cFields; i++)
1531         {
1532             if(pInfoArrayOut[i].m_MD != mdFieldDefNil)
1533             {
1534                 if (pInfoArrayOut[i].m_offset == (UINT32)-1)
1535                 {
1536                     LPCUTF8 szFieldName;
1537                     if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1538                     {
1539                         szFieldName = "Invalid FieldDef record";
1540                     }
1541                     pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, 
1542                                                                    cl,
1543                                                                    szFieldName,
1544                                                                    IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
1545                 }
1546                 else if ((INT)pInfoArrayOut[i].m_offset < 0)
1547                 {
1548                     LPCUTF8 szFieldName;
1549                     if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1550                     {
1551                         szFieldName = "Invalid FieldDef record";
1552                     }
1553                     pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, 
1554                                                                    cl,
1555                                                                    szFieldName,
1556                                                                    IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
1557                 }
1558             }
1559                 
1560             *pSortArrayEnd = &pInfoArrayOut[i];
1561             pSortArrayEnd++;
1562         }
1563     }
1564
1565     //=====================================================================
1566     // Phase 2: Compute the native size (in bytes) of each field.
1567     // Store this in pInfoArrayOut[].cbNativeSize;
1568     //=====================================================================
1569
1570     // Now compute the native size of each field
1571     for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1572     {
1573         UINT8 nft = pfwalk->m_nft;
1574         pEEClassLayoutInfoOut->m_numCTMFields++;
1575
1576         // If the NFT's size never changes, it is stored in the database.
1577         UINT32 cbNativeSize = NFTDataBase[nft].m_cbNativeSize;
1578
1579         if (cbNativeSize == 0)
1580         {
1581             // Size of 0 means NFT's size is variable, so we have to figure it
1582             // out case by case.
1583             cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
1584         }
1585         pfwalk->m_cbNativeSize = cbNativeSize;
1586     }
1587
1588     if (pEEClassLayoutInfoOut->m_numCTMFields)
1589     {
1590         pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
1591
1592         // Bring in the parent's fieldmarshalers
1593         if (fHasNonTrivialParent)
1594         {
1595             CONSISTENCY_CHECK(fParentHasLayout);
1596             PREFAST_ASSUME(pParentLayoutInfo != NULL);  // See if (fParentHasLayout) branch above
1597
1598             UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
1599
1600             BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
1601             BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
1602
1603             for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
1604             {
1605                 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1606                 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1607
1608                 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
1609             }
1610         }
1611
1612     }
1613
1614
1615     //=====================================================================
1616     // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset
1617     // of each field and the size of the total structure. We do the layout
1618     // according to standard VC layout rules:
1619     //
1620     //   Each field has an alignment requirement. The alignment-requirement
1621     //   of a scalar field is the smaller of its size and the declared packsize.
1622     //   The alighnment-requirement of a struct field is the smaller of the
1623     //   declared packsize and the largest of the alignment-requirement
1624     //   of its fields. The alignment requirement of an array is that
1625     //   of one of its elements.
1626     //
1627     //   In addition, each struct gets padding at the end to ensure
1628     //   that an array of such structs contain no unused space between
1629     //   elements.
1630     //=====================================================================
1631     {
1632         BYTE   LargestAlignmentRequirement = 1;
1633         UINT32 cbCurOffset = 0;
1634
1635         // Treat base class as an initial member.
1636         if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize))
1637             COMPlusThrowOM();
1638
1639         if (fParentHasLayout)
1640         {
1641             BYTE alignmentRequirement;
1642             
1643             alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers());
1644     
1645             LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);                                          
1646         }
1647
1648         // Start with the size inherited from the parent (if any).
1649         unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize;
1650      
1651         LayoutRawFieldInfo **pSortWalk;
1652         for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1653         {
1654             pfwalk = *pSortWalk;
1655     
1656             BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement());
1657             if (!(alignmentRequirement == 1 ||
1658                      alignmentRequirement == 2 ||
1659                      alignmentRequirement == 4 ||
1660                   alignmentRequirement == 8 ||
1661                   alignmentRequirement == 16 ||
1662                   alignmentRequirement == 32))
1663             {
1664                 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1665             }
1666     
1667             alignmentRequirement = min(alignmentRequirement, packingSize);
1668     
1669             LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1670     
1671             // This assert means I forgot to special-case some NFT in the
1672             // above switch.
1673             _ASSERTE(alignmentRequirement <= 32);
1674     
1675             // Check if this field is overlapped with other(s)
1676             pfwalk->m_fIsOverlapped = FALSE;
1677             if (fExplicitOffsets) {
1678                 LayoutRawFieldInfo *pfwalk1;
1679                 DWORD dwBegin = pfwalk->m_offset;
1680                 DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize;
1681                 for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++)
1682                 {
1683                     if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue;
1684                     pfwalk->m_fIsOverlapped = TRUE;
1685                     pfwalk1->m_fIsOverlapped = TRUE;
1686                 }
1687             }
1688             else
1689             {
1690                 // Insert enough padding to align the current data member.
1691                 while (cbCurOffset % alignmentRequirement)
1692                 {
1693                     if (!SafeAddUINT32(&cbCurOffset, 1))
1694                         COMPlusThrowOM();
1695                 }
1696     
1697                 // Insert current data member.
1698                 pfwalk->m_offset = cbCurOffset;
1699     
1700                 // if we overflow we will catch it below
1701                 cbCurOffset += pfwalk->m_cbNativeSize;
1702             } 
1703     
1704             unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize;
1705             if (fieldEnd < pfwalk->m_offset)
1706                 COMPlusThrowOM();
1707     
1708                 // size of the structure is the size of the last field.  
1709             if (fieldEnd > calcTotalSize)
1710                 calcTotalSize = fieldEnd;
1711         }
1712     
1713         ULONG clstotalsize = 0;
1714         if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1715         {
1716             clstotalsize = 0;
1717         }
1718         
1719         if (clstotalsize != 0)
1720         {
1721             if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize))
1722                 COMPlusThrowOM();
1723     
1724             // size must be large enough to accomodate layout. If not, we use the layout size instead.
1725             if (clstotalsize < calcTotalSize)
1726             {
1727                 clstotalsize = calcTotalSize;
1728             }
1729             calcTotalSize = clstotalsize;   // use the size they told us 
1730         } 
1731         else
1732         {
1733             // The did not give us an explict size, so lets round up to a good size (for arrays) 
1734             while (calcTotalSize % LargestAlignmentRequirement != 0)
1735             {
1736                 if (!SafeAddUINT32(&calcTotalSize, 1))
1737                     COMPlusThrowOM();
1738             }
1739         }
1740         
1741         // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
1742         // that we don't expose some overflow bug later on.
1743         if (calcTotalSize >= MAX_SIZE_FOR_INTEROP)
1744             COMPlusThrowOM();
1745
1746         // This is a zero-sized struct - need to record the fact and bump it up to 1.
1747         if (calcTotalSize == 0)
1748         {
1749             pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
1750             calcTotalSize = 1;
1751         }
1752     
1753         pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
1754     
1755         // The packingSize acts as a ceiling on all individual alignment
1756         // requirements so it follows that the largest alignment requirement
1757         // is also capped.
1758         _ASSERTE(LargestAlignmentRequirement <= packingSize);
1759         pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1760     }
1761
1762
1763
1764     //=====================================================================
1765     // Phase 4: Now we do the same thing again for managedsequential layout.
1766     //=====================================================================
1767     if (!fDisqualifyFromManagedSequential)
1768     {
1769         BYTE   LargestAlignmentRequirement = 1;
1770         UINT32 cbCurOffset = 0;
1771     
1772         if (pParentMT && pParentMT->IsManagedSequential())
1773         {
1774             // Treat base class as an initial member.
1775             if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes()))
1776                 COMPlusThrowOM();
1777     
1778             BYTE alignmentRequirement = 0;
1779                 
1780             alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers);
1781     
1782             LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);                                          
1783         }
1784     
1785         // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures.
1786         // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes
1787         //       can be ManagedSequential and ValueTypes can not be inherited from.
1788         unsigned calcTotalSize = 1;
1789      
1790         LayoutRawFieldInfo **pSortWalk;
1791         for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1792         {
1793             pfwalk = *pSortWalk;
1794     
1795             BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq));
1796             if (!(alignmentRequirement == 1 ||
1797                      alignmentRequirement == 2 ||
1798                      alignmentRequirement == 4 ||
1799                   alignmentRequirement == 8 ||
1800                   alignmentRequirement == 16 ||
1801                   alignmentRequirement == 32))
1802             {
1803                 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1804             }
1805             
1806             alignmentRequirement = min(alignmentRequirement, packingSize);
1807             
1808             LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1809             
1810             _ASSERTE(alignmentRequirement <= 32);
1811             
1812             // Insert enough padding to align the current data member.
1813             while (cbCurOffset % alignmentRequirement)
1814             {
1815                 if (!SafeAddUINT32(&cbCurOffset, 1))
1816                     COMPlusThrowOM();
1817             }
1818             
1819             // Insert current data member.
1820             pfwalk->m_managedOffset = cbCurOffset;
1821             
1822             // if we overflow we will catch it below
1823             cbCurOffset += pfwalk->m_managedSize;
1824             
1825             unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize;
1826             if (fieldEnd < pfwalk->m_managedOffset)
1827                 COMPlusThrowOM();
1828             
1829                 // size of the structure is the size of the last field.  
1830             if (fieldEnd > calcTotalSize)
1831                 calcTotalSize = fieldEnd;
1832             
1833 #ifdef _DEBUG
1834             // @perf: If the type is blittable, the managed and native layouts have to be identical
1835             // so they really shouldn't be calculated twice. Until this code has been well tested and
1836             // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1837             // case.
1838             if (pEEClassLayoutInfoOut->IsBlittable())
1839             {
1840                 _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset);
1841                 _ASSERTE(pfwalk->m_managedSize   == pfwalk->m_cbNativeSize);
1842             }
1843 #endif
1844         } //for
1845         
1846         ULONG clstotalsize = 0;
1847         if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1848         {
1849             clstotalsize = 0;
1850         }
1851         
1852         if (clstotalsize != 0)
1853         {
1854             pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
1855             
1856             if (pParentMT && pParentMT->IsManagedSequential())
1857             {
1858                 // Treat base class as an initial member.
1859                 UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes();
1860                 if (!SafeAddULONG(&clstotalsize, parentSize))
1861                     COMPlusThrowOM();
1862             }
1863     
1864             // size must be large enough to accomodate layout. If not, we use the layout size instead.
1865             if (clstotalsize < calcTotalSize)
1866             {
1867                 clstotalsize = calcTotalSize;
1868             }
1869             calcTotalSize = clstotalsize;   // use the size they told us 
1870         } 
1871         else
1872         {
1873             // The did not give us an explict size, so lets round up to a good size (for arrays) 
1874             while (calcTotalSize % LargestAlignmentRequirement != 0)
1875             {
1876                 if (!SafeAddUINT32(&calcTotalSize, 1))
1877                     COMPlusThrowOM();
1878             }
1879         } 
1880     
1881         pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
1882
1883         // The packingSize acts as a ceiling on all individual alignment
1884         // requirements so it follows that the largest alignment requirement
1885         // is also capped.
1886         _ASSERTE(LargestAlignmentRequirement <= packingSize);
1887         pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1888
1889 #ifdef _DEBUG
1890             // @perf: If the type is blittable, the managed and native layouts have to be identical
1891             // so they really shouldn't be calculated twice. Until this code has been well tested and
1892             // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1893             // case.
1894             if (pEEClassLayoutInfoOut->IsBlittable())
1895             {
1896                 _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
1897                 _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
1898             }
1899 #endif
1900     } //if
1901
1902     pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
1903
1904 #ifdef _DEBUG
1905     {
1906         BOOL illegalMarshaler = FALSE;
1907         
1908         LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
1909         LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
1910         LOG((LF_INTEROP, LL_INFO100000, "Packsize      = %lu\n", (ULONG)packingSize));
1911         LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
1912         LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
1913         for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1914         {
1915             LPCUTF8 fieldname;
1916             if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
1917             {
1918                 fieldname = "??";
1919             }
1920             LOG((LF_INTEROP, LL_INFO100000, "+%-5lu  ", (ULONG)(pfwalk->m_offset)));
1921             LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
1922             LOG((LF_INTEROP, LL_INFO100000, "\n"));
1923
1924             if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
1925                 illegalMarshaler = TRUE;             
1926         }
1927
1928         // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
1929         if (fHasNonTrivialParent)
1930         {
1931             FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
1932             for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
1933             {
1934                 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
1935                     illegalMarshaler = TRUE;                                 
1936                 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
1937             }
1938         }
1939         
1940         LOG((LF_INTEROP, LL_INFO100000, "+%-5lu   EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
1941         LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
1942     }
1943 #endif
1944     return;
1945 }
1946 #ifdef _PREFAST_
1947 #pragma warning(pop)
1948 #endif
1949
1950
1951 #ifndef CROSSGEN_COMPILE
1952
1953 //=======================================================================
1954 // For each reference-typed FieldMarshaler field, marshals the current CLR value
1955 // to a new native instance and stores it in the fixed portion of the FieldMarshaler.
1956 //
1957 // This function does not attempt to delete the native value that it overwrites.
1958 //
1959 // If there is a SafeHandle field, ppCleanupWorkListOnStack must be non-null, otherwise
1960 // InvalidOperationException is thrown.
1961 //=======================================================================
1962 VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE* pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
1963 {       
1964     CONTRACTL
1965     {
1966         THROWS;
1967         GC_TRIGGERS;
1968         MODE_COOPERATIVE;
1969         PRECONDITION(CheckPointer(pMT));
1970     }
1971     CONTRACTL_END;
1972     
1973     FieldMarshaler* pFM                   = pMT->GetLayoutInfo()->GetFieldMarshalers();
1974     UINT  numReferenceFields              = pMT->GetLayoutInfo()->GetNumCTMFields();
1975     
1976     OBJECTREF pCLRValue    = NULL;
1977     LPVOID scalar           = NULL;
1978     
1979     GCPROTECT_BEGIN(pCLRValue)
1980     GCPROTECT_BEGININTERIOR(scalar)
1981     {
1982         g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
1983
1984         while (numReferenceFields--)
1985         {
1986             pFM->Restore();
1987
1988             DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
1989
1990             if (pFM->IsScalarMarshaler())
1991             {
1992                 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
1993                 // Note this will throw for FieldMarshaler_Illegal
1994                 pFM->ScalarUpdateNative(scalar, pNativeData + pFM->GetExternalOffset() );
1995                 
1996             }
1997             else if (pFM->IsNestedValueClassMarshaler())
1998             {
1999                 pFM->NestedValueClassUpdateNative((const VOID **)ppProtectedManagedData, internalOffset + offsetbias, pNativeData + pFM->GetExternalOffset(),
2000                     ppCleanupWorkListOnStack);
2001             }
2002             else
2003             {
2004                 pCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2005                 pFM->UpdateNative(&pCLRValue, pNativeData + pFM->GetExternalOffset(), ppCleanupWorkListOnStack);
2006                 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), pCLRValue);
2007             }
2008
2009             // The cleanup work list is not used to clean up the native contents. It is used
2010             // to handle cleanup of any additionnal resources the FieldMarshalers allocate.
2011
2012             ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2013         }
2014     }
2015     GCPROTECT_END();
2016     GCPROTECT_END();
2017 }
2018
2019
2020 VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2021 {        
2022     CONTRACTL
2023     {
2024         THROWS;
2025         GC_TRIGGERS;
2026         MODE_COOPERATIVE;
2027         PRECONDITION(CheckPointer(ppProtectedManagedData));
2028     }
2029     CONTRACTL_END;
2030
2031     MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2032     _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2033     UINT32   cbsize = pMT->GetNativeSize();
2034
2035     if (pMT->IsBlittable())
2036     {
2037         memcpyNoGCRefs(pNativeData, (*ppProtectedManagedData)->GetData(), cbsize);
2038     }
2039     else
2040     {
2041         // This allows us to do a partial LayoutDestroyNative in the case of
2042         // a marshaling error on one of the fields.
2043         FillMemory(pNativeData, cbsize, 0);
2044         NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2045         
2046         LayoutUpdateNative( (VOID**)ppProtectedManagedData,
2047                                 Object::GetOffsetOfFirstField(),
2048                                 pMT,
2049                                 pNativeData,
2050                                 ppCleanupWorkListOnStack);
2051         
2052         nld.SuppressRelease();
2053     }
2054
2055 }
2056
2057
2058 VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData)
2059 {       
2060     CONTRACTL
2061     {
2062         THROWS;
2063         GC_TRIGGERS;
2064         MODE_COOPERATIVE;
2065     }
2066     CONTRACTL_END;
2067     
2068     MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2069     _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2070     UINT32   cbsize = pMT->GetNativeSize();
2071
2072     if (pMT->IsBlittable())
2073     {
2074         memcpyNoGCRefs((*ppProtectedManagedData)->GetData(), pNativeData, cbsize);
2075     }
2076     else
2077     {
2078         LayoutUpdateCLR((VOID**)ppProtectedManagedData,
2079                             Object::GetOffsetOfFirstField(),
2080                             pMT,
2081                             (BYTE*)pNativeData
2082                            );
2083     }
2084 }
2085
2086
2087
2088 //=======================================================================
2089 // For each reference-typed FieldMarshaler field, marshals the current CLR value
2090 // to a new CLR instance and stores it in the GC portion of the FieldMarshaler.
2091 //
2092 // If fDeleteNativeCopies is true, it will also destroy the native version.
2093 //
2094 // NOTE: To avoid error-path leaks, this function attempts to destroy
2095 // all of the native fields even if one or more of the conversions fail.
2096 //=======================================================================
2097 VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData)
2098 {        
2099     CONTRACTL
2100     {
2101         THROWS;
2102         GC_TRIGGERS;
2103         MODE_COOPERATIVE;
2104         PRECONDITION(CheckPointer(pMT));
2105     }
2106     CONTRACTL_END;
2107
2108     // Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and
2109     // are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub).
2110
2111     FieldMarshaler* pFM                   = pMT->GetLayoutInfo()->GetFieldMarshalers();
2112     UINT  numReferenceFields              = pMT->GetLayoutInfo()->GetNumCTMFields(); 
2113
2114     struct _gc
2115     {
2116         OBJECTREF pCLRValue;
2117         OBJECTREF pOldCLRValue;
2118     } gc;
2119
2120     gc.pCLRValue    = NULL;
2121     gc.pOldCLRValue = NULL;
2122     LPVOID scalar    = NULL;
2123     
2124     GCPROTECT_BEGIN(gc)
2125     GCPROTECT_BEGININTERIOR(scalar)
2126     {
2127         g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
2128
2129         while (numReferenceFields--)
2130         {
2131             pFM->Restore();
2132
2133             DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2134
2135             if (pFM->IsScalarMarshaler())
2136             {
2137                 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2138                 // Note this will throw for FieldMarshaler_Illegal
2139                 pFM->ScalarUpdateCLR( pNativeData + pFM->GetExternalOffset(), scalar);
2140             }
2141             else if (pFM->IsNestedValueClassMarshaler())
2142             {
2143                 pFM->NestedValueClassUpdateCLR(pNativeData + pFM->GetExternalOffset(), ppProtectedManagedData, internalOffset + offsetbias);
2144             }
2145             else
2146             {
2147                 gc.pOldCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2148                 pFM->UpdateCLR( pNativeData + pFM->GetExternalOffset(), &gc.pCLRValue, &gc.pOldCLRValue );
2149                 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), gc.pCLRValue );
2150             }
2151
2152             ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2153         }
2154     }
2155     GCPROTECT_END();
2156     GCPROTECT_END();
2157 }
2158
2159
2160 VOID LayoutDestroyNative(LPVOID pNative, MethodTable *pMT)
2161 {
2162     CONTRACTL
2163     {
2164         NOTHROW;
2165         GC_TRIGGERS;
2166         MODE_ANY;
2167         PRECONDITION(CheckPointer(pMT));
2168     }
2169     CONTRACTL_END;
2170     
2171     FieldMarshaler *pFM                   = pMT->GetLayoutInfo()->GetFieldMarshalers();
2172     UINT  numReferenceFields              = pMT->GetLayoutInfo()->GetNumCTMFields();
2173     BYTE *pNativeData                     = (BYTE*)pNative;
2174
2175     while (numReferenceFields--)
2176     {
2177         pFM->DestroyNative( pNativeData + pFM->GetExternalOffset() );
2178         ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2179     }
2180 }
2181
2182 VOID FmtClassDestroyNative(LPVOID pNative, MethodTable *pMT)
2183 {       
2184     CONTRACTL
2185     {
2186         NOTHROW;
2187         GC_TRIGGERS;
2188         MODE_ANY;
2189         PRECONDITION(CheckPointer(pMT));
2190     }
2191     CONTRACTL_END;
2192     
2193     if (pNative)
2194     {
2195         if (!(pMT->IsBlittable()))
2196         {
2197             _ASSERTE(pMT->HasLayout());
2198             LayoutDestroyNative(pNative, pMT);
2199         }
2200     }
2201 }
2202
2203 VOID FmtValueTypeUpdateNative(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2204 {        
2205     CONTRACTL
2206     {
2207         THROWS;
2208         GC_TRIGGERS;
2209         MODE_COOPERATIVE;
2210         PRECONDITION(CheckPointer(pMT));
2211     }
2212     CONTRACTL_END;
2213     
2214     _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2215     UINT32   cbsize = pMT->GetNativeSize();
2216
2217     if (pMT->IsBlittable())
2218     {
2219         memcpyNoGCRefs(pNativeData, pProtectedManagedData, cbsize);
2220     }
2221     else
2222     {
2223         // This allows us to do a partial LayoutDestroyNative in the case of
2224         // a marshaling error on one of the fields.
2225         FillMemory(pNativeData, cbsize, 0);
2226         
2227         NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2228         
2229         LayoutUpdateNative( (VOID**)pProtectedManagedData,
2230                                 0,
2231                                 pMT,
2232                                 pNativeData,
2233                                 ppCleanupWorkListOnStack);
2234         
2235         nld.SuppressRelease();
2236     }
2237 }
2238
2239 VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData)
2240 {       
2241     CONTRACTL
2242     {
2243         THROWS;
2244         GC_TRIGGERS;
2245         MODE_COOPERATIVE;
2246         PRECONDITION(CheckPointer(pMT));
2247     }
2248     CONTRACTL_END;
2249
2250     _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2251     UINT32   cbsize = pMT->GetNativeSize();
2252
2253     if (pMT->IsBlittable())
2254     {
2255         memcpyNoGCRefs(pProtectedManagedData, pNativeData, cbsize);
2256     }
2257     else
2258     {
2259         LayoutUpdateCLR((VOID**)pProtectedManagedData,
2260                             0,
2261                             pMT,
2262                             (BYTE*)pNativeData);
2263     }
2264 }
2265
2266
2267 #ifdef FEATURE_COMINTEROP
2268
2269 //=======================================================================
2270 // BSTR <--> System.String
2271 // See FieldMarshaler for details.
2272 //=======================================================================
2273 VOID FieldMarshaler_BSTR::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
2274 {
2275     CONTRACTL
2276     {
2277         THROWS;
2278         GC_NOTRIGGER;
2279         MODE_COOPERATIVE;
2280         INJECT_FAULT(COMPlusThrowOM());
2281         PRECONDITION(CheckPointer(pNativeValue));
2282     }
2283     CONTRACTL_END;
2284
2285     STRINGREF pString;
2286     *((OBJECTREF*)&pString) = *pCLRValue;
2287     
2288     if (pString == NULL)
2289         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2290     else
2291     {
2292         BSTR pBSTR = SysAllocStringLen(pString->GetBuffer(), pString->GetStringLength());
2293         if (!pBSTR)
2294             COMPlusThrowOM();
2295
2296         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pBSTR);        
2297     }
2298 }
2299
2300
2301 //=======================================================================
2302 // BSTR <--> System.String
2303 // See FieldMarshaler for details.
2304 //=======================================================================
2305 VOID FieldMarshaler_BSTR::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
2306 {
2307     STATIC_CONTRACT_THROWS;
2308     STATIC_CONTRACT_GC_TRIGGERS;
2309     STATIC_CONTRACT_MODE_COOPERATIVE;
2310
2311     _ASSERTE(NULL != pNativeValue);
2312     _ASSERTE(NULL != ppProtectedCLRValue);
2313
2314     STRINGREF pString;
2315     BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2316     
2317     if (!pBSTR)
2318         pString = NULL;
2319     else
2320     {
2321         struct Param : CallOutFilterParam {
2322             int             length;
2323             BSTR            pBSTR;
2324         }; Param param;
2325
2326         param.OneShot = TRUE;
2327         param.length = 0;
2328         param.pBSTR = pBSTR;
2329
2330         PAL_TRY(Param *, pParam, &param)
2331         {
2332             pParam->length = SysStringLen(pParam->pBSTR);
2333         }
2334         PAL_EXCEPT_FILTER(CallOutFilter)
2335         {
2336             _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
2337         }
2338         PAL_ENDTRY;
2339         
2340         pString = StringObject::NewString(pBSTR, param.length);
2341     }
2342
2343     *((STRINGREF*)ppProtectedCLRValue) = pString;
2344 }
2345
2346
2347 //=======================================================================
2348 // BSTR <--> System.String
2349 // See FieldMarshaler for details.
2350 //=======================================================================
2351 VOID FieldMarshaler_BSTR::DestroyNativeImpl(LPVOID pNativeValue) const 
2352 {
2353     CONTRACTL
2354     {
2355         NOTHROW;
2356         GC_NOTRIGGER;
2357         MODE_ANY;
2358         PRECONDITION(CheckPointer(pNativeValue));
2359     }
2360     CONTRACTL_END;
2361
2362     BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2363     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2364     
2365     if (pBSTR)
2366     {
2367         _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
2368         // BSTR has been created, which means oleaut32 should have been loaded.
2369         // Delay load will not fail.
2370         CONTRACT_VIOLATION(ThrowsViolation);
2371         SysFreeString(pBSTR);
2372     }
2373 }
2374
2375 //===========================================================================================
2376 // Windows.Foundation.IReference'1<-- System.Nullable'1
2377 //
2378 VOID FieldMarshaler_Nullable::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
2379 {
2380     CONTRACTL
2381     {
2382         THROWS;
2383         GC_TRIGGERS;
2384         MODE_COOPERATIVE;
2385         INJECT_FAULT(COMPlusThrowOM());
2386         PRECONDITION(CheckPointer(pNative));
2387         PRECONDITION(CheckPointer(pCLR));
2388     }
2389     CONTRACTL_END;
2390
2391     IUnknown *pUnk = NULL;
2392
2393     // ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct
2394     MethodDescCallSite convertToNative(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE)));
2395     ARG_SLOT args[] =
2396     {
2397         PtrToArgSlot(pCLR)
2398     };
2399
2400     pUnk = (IUnknown*) convertToNative.Call_RetLPVOID(args);
2401
2402     MAYBE_UNALIGNED_WRITE(pNative, _PTR, pUnk);
2403 }
2404
2405 //===========================================================================================
2406 // Windows.Foundation.IReference'1--> System.Nullable'1
2407 //
2408 VOID FieldMarshaler_Nullable::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
2409 {
2410     CONTRACTL
2411     {
2412         THROWS;
2413         GC_TRIGGERS;
2414         MODE_COOPERATIVE;
2415         PRECONDITION(CheckPointer(pNative));
2416         PRECONDITION(CheckPointer(pCLR));
2417     }
2418     CONTRACTL_END;
2419
2420     IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2421
2422     MethodDescCallSite convertToManaged(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED_RET_VOID)));
2423
2424     ARG_SLOT args[] =
2425     {
2426         PtrToArgSlot(pUnk),
2427         PtrToArgSlot(pCLR)
2428     };
2429
2430     //ConvertToManaged<T>(Intptr pNative, ref Nullable<T> retObj) where T : struct;
2431     convertToManaged.Call(args);
2432 }
2433
2434 //===========================================================================================
2435 // Windows.Foundation.IReference'1<--> System.Nullable'1
2436 //
2437 VOID FieldMarshaler_Nullable::DestroyNativeImpl(const VOID* pNative) const
2438
2439     CONTRACTL
2440     {
2441         NOTHROW;
2442         GC_TRIGGERS;
2443         MODE_ANY;
2444         PRECONDITION(CheckPointer(pNative));
2445     }
2446     CONTRACTL_END;
2447
2448     IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2449     MAYBE_UNALIGNED_WRITE(pNative, _PTR, NULL);
2450
2451     if (pUnk != NULL)
2452     {
2453         ULONG cbRef = SafeRelease(pUnk);
2454         LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
2455     }
2456 }
2457
2458 //=======================================================================
2459 // HSTRING <--> System.String
2460 // See FieldMarshaler for details.
2461 //=======================================================================
2462 VOID FieldMarshaler_HSTRING::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2463 {
2464     CONTRACTL
2465     {
2466         THROWS;
2467         GC_TRIGGERS;
2468         MODE_COOPERATIVE;
2469         PRECONDITION(CheckPointer(pCLRValue));
2470         PRECONDITION(CheckPointer(pNativeValue));
2471     }
2472     CONTRACTL_END;
2473
2474     if (!WinRTSupported())
2475     {
2476         COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2477     }
2478
2479     STRINGREF stringref = (STRINGREF)(*pCLRValue);
2480
2481     if (stringref == NULL)
2482     {
2483         DefineFullyQualifiedNameForClassW();
2484         StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
2485
2486         SString errorString;
2487         errorString.LoadResource(CCompRC::Error, IDS_EE_BADMARSHALFIELD_NULL_HSTRING);
2488
2489         COMPlusThrow(kMarshalDirectiveException,
2490                      IDS_EE_BADMARSHALFIELD_ERROR_MSG,
2491                      GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
2492                      ssFieldName.GetUnicode(),
2493                      errorString.GetUnicode());
2494     }
2495
2496     HSTRING hstring;
2497     IfFailThrow(WindowsCreateString(stringref->GetBuffer(), stringref->GetStringLength(), &hstring));
2498
2499     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, hstring);
2500 }
2501
2502 //=======================================================================
2503 // HSTRING <--> System.String
2504 // See FieldMarshaler for details.
2505 //=======================================================================
2506 VOID FieldMarshaler_HSTRING::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2507 {
2508     CONTRACTL
2509     {
2510         THROWS;
2511         GC_TRIGGERS;
2512         MODE_COOPERATIVE;
2513         PRECONDITION(CheckPointer(pNativeValue));
2514         PRECONDITION(CheckPointer(ppProtectedCLRValue));
2515     }
2516     CONTRACTL_END;
2517
2518     if (!WinRTSupported())
2519     {
2520         COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2521     }
2522
2523     // NULL HSTRINGS are equivilent to empty strings
2524     UINT32 cchString = 0;
2525     LPCWSTR pwszString = W("");
2526
2527     HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2528     if (hstring != NULL)
2529     {
2530         pwszString = WindowsGetStringRawBuffer(hstring, &cchString);
2531     }
2532
2533     STRINGREF stringref = StringObject::NewString(pwszString, cchString);
2534     *((STRINGREF *)ppProtectedCLRValue) = stringref;
2535 }
2536
2537 //=======================================================================
2538 // HSTRING <--> System.String
2539 // See FieldMarshaler for details.
2540 //=======================================================================
2541 VOID FieldMarshaler_HSTRING::DestroyNativeImpl(LPVOID pNativeValue) const
2542 {
2543     CONTRACTL
2544     {
2545         NOTHROW;
2546         GC_NOTRIGGER;
2547         MODE_ANY;
2548         PRECONDITION(CheckPointer(pNativeValue));
2549     }
2550     CONTRACTL_END;
2551
2552     HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2553     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2554
2555     if (hstring != NULL)
2556     {
2557         // We need this for code:System.Runtime.InteropServices.Marshal.DestroyStructure (user can explicitly call it)
2558         if (WinRTSupported())
2559         {
2560             // If WinRT is supported we've already loaded combase.dll, which means
2561             // this delay load will succeed
2562             CONTRACT_VIOLATION(ThrowsViolation);
2563             WindowsDeleteString(hstring);
2564         }
2565     }
2566 }
2567
2568 //=======================================================================================
2569 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2570 // 
2571 VOID FieldMarshaler_SystemType::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2572 {
2573     CONTRACTL
2574     {
2575         THROWS;
2576         GC_TRIGGERS;
2577         MODE_COOPERATIVE;
2578         PRECONDITION(CheckPointer(pCLRValue));
2579         PRECONDITION(CheckPointer(pNativeValue));
2580     }
2581     CONTRACTL_END;
2582     
2583     // ConvertToNative(System.Type managedType, TypeName *pTypeName)
2584     MethodDescCallSite convertToNative(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE);
2585     ARG_SLOT args[] =
2586     {
2587         ObjToArgSlot(*pCLRValue),
2588         PtrToArgSlot(pNativeValue)
2589     };
2590     convertToNative.Call(args);
2591 }
2592
2593 //=======================================================================================
2594 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2595 // 
2596 VOID FieldMarshaler_SystemType::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2597 {
2598     CONTRACTL
2599     {
2600         THROWS;
2601         GC_TRIGGERS;
2602         MODE_COOPERATIVE;
2603         PRECONDITION(CheckPointer(pNativeValue));
2604         PRECONDITION(CheckPointer(ppProtectedCLRValue));
2605     }
2606     CONTRACTL_END;
2607     
2608     // ConvertToManaged(TypeName *pTypeName, out System.Type)
2609     MethodDescCallSite convertToManaged(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED);
2610     ARG_SLOT args[] =
2611     {
2612         PtrToArgSlot(pNativeValue),
2613         PtrToArgSlot(ppProtectedCLRValue)
2614     };
2615     
2616     convertToManaged.Call(args);
2617 }
2618
2619 //=======================================================================================
2620 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2621 // Clear the HSTRING field
2622 // 
2623 VOID FieldMarshaler_SystemType::DestroyNativeImpl(LPVOID pNativeValue) const
2624 {
2625     CONTRACTL
2626     {
2627         NOTHROW;
2628         GC_NOTRIGGER;
2629         MODE_ANY;
2630         PRECONDITION(CheckPointer(pNativeValue));
2631         PRECONDITION(WinRTSupported());
2632     }
2633     CONTRACTL_END;
2634
2635     //
2636     // Call WindowsDeleteString instead of SystemTypeMarshaler.ClearNative
2637     // because WindowsDeleteString does not throw and is much faster
2638     //    
2639     size_t offset = offsetof(TypeNameNative, typeName);
2640     HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ((LPBYTE) pNativeValue + offset , _PTR);
2641     MAYBE_UNALIGNED_WRITE((LPBYTE) pNativeValue + offset, _PTR, NULL);
2642     
2643     if (hstring != NULL)
2644     {
2645         // Note: we've already loaded combase.dll, which means this delay load will succeed
2646         CONTRACT_VIOLATION(ThrowsViolation);
2647         WindowsDeleteString(hstring);
2648     }
2649 }
2650
2651 //=======================================================================================
2652 // Windows.Foundation.HResult <--> System.Exception
2653 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2654 // 
2655 VOID FieldMarshaler_Exception::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2656 {
2657     CONTRACTL
2658     {
2659         THROWS;
2660         GC_TRIGGERS;
2661         MODE_COOPERATIVE;
2662         PRECONDITION(CheckPointer(pCLRValue));
2663         PRECONDITION(CheckPointer(pNativeValue));
2664     }
2665     CONTRACTL_END;
2666     
2667     // int ConvertToNative(Exception ex)
2668     MethodDescCallSite convertToNative(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE);
2669     ARG_SLOT args[] =
2670     {
2671         ObjToArgSlot(*pCLRValue)
2672     };
2673     int iReturnedValue = convertToNative.Call_RetI4(args);
2674     MAYBE_UNALIGNED_WRITE(pNativeValue, 32, iReturnedValue);
2675 }
2676
2677 //=======================================================================================
2678 // Windows.Foundation.HResult <--> System.Exception
2679 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2680 // 
2681 VOID FieldMarshaler_Exception::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2682 {
2683     CONTRACTL
2684     {
2685         THROWS;
2686         GC_TRIGGERS;
2687         MODE_COOPERATIVE;
2688         PRECONDITION(CheckPointer(pNativeValue));
2689         PRECONDITION(CheckPointer(ppProtectedCLRValue));
2690     }
2691     CONTRACTL_END;
2692     
2693     // Exception ConvertToManaged(int hr)
2694     MethodDescCallSite convertToManaged(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED);
2695     ARG_SLOT args[] =
2696     {
2697         (ARG_SLOT)MAYBE_UNALIGNED_READ(pNativeValue, 32)
2698     };
2699     *ppProtectedCLRValue = convertToManaged.Call_RetOBJECTREF(args);
2700 }
2701
2702 #endif // FEATURE_COMINTEROP
2703
2704
2705 //=======================================================================
2706 // Nested structure conversion
2707 // See FieldMarshaler for details.
2708 //=======================================================================
2709 VOID FieldMarshaler_NestedLayoutClass::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
2710 {
2711     CONTRACTL
2712     {
2713         THROWS;
2714         GC_TRIGGERS;
2715         MODE_COOPERATIVE;
2716         INJECT_FAULT(COMPlusThrowOM());
2717         PRECONDITION(CheckPointer(pNativeValue));
2718     }
2719     CONTRACTL_END;
2720
2721     UINT32 cbNativeSize = GetMethodTable()->GetNativeSize();
2722
2723     if (*pCLRValue == NULL)
2724     {
2725         ZeroMemoryInGCHeap(pNativeValue, cbNativeSize);
2726     }
2727     else
2728     {
2729         LayoutUpdateNative((LPVOID*)pCLRValue, Object::GetOffsetOfFirstField(), 
2730                            GetMethodTable(), (BYTE*)pNativeValue, ppCleanupWorkListOnStack);
2731     }
2732
2733 }
2734
2735
2736 //=======================================================================
2737 // Nested structure conversion
2738 // See FieldMarshaler for details.
2739 //=======================================================================
2740 VOID FieldMarshaler_NestedLayoutClass::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
2741 {
2742     CONTRACTL
2743     {
2744         THROWS;
2745         GC_TRIGGERS;
2746         MODE_COOPERATIVE;
2747         INJECT_FAULT(COMPlusThrowOM());
2748         PRECONDITION(CheckPointer(pNativeValue));
2749         PRECONDITION(CheckPointer(ppProtectedCLRValue));
2750     }
2751     CONTRACTL_END;
2752
2753     *ppProtectedCLRValue = GetMethodTable()->Allocate();
2754
2755     LayoutUpdateCLR( (LPVOID*)ppProtectedCLRValue,
2756                          Object::GetOffsetOfFirstField(),
2757                          GetMethodTable(),
2758                          (BYTE *)pNativeValue);
2759
2760 }
2761
2762
2763 //=======================================================================
2764 // Nested structure conversion
2765 // See FieldMarshaler for details.
2766 //=======================================================================
2767 VOID FieldMarshaler_NestedLayoutClass::DestroyNativeImpl(LPVOID pNativeValue) const 
2768 {
2769     CONTRACTL
2770     {
2771         NOTHROW;
2772         GC_TRIGGERS;
2773         MODE_ANY;
2774         PRECONDITION(CheckPointer(pNativeValue));
2775     }
2776     CONTRACTL_END;
2777
2778     LayoutDestroyNative(pNativeValue, GetMethodTable());
2779 }
2780
2781 #endif // CROSSGEN_COMPILE
2782
2783
2784 //=======================================================================
2785 // Nested structure conversion
2786 // See FieldMarshaler for details.
2787 //=======================================================================
2788 UINT32 FieldMarshaler_NestedLayoutClass::NativeSizeImpl() const
2789 {
2790     CONTRACTL
2791     {
2792         NOTHROW;
2793         GC_NOTRIGGER;
2794         MODE_ANY;
2795     }
2796     CONTRACTL_END;
2797
2798     return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2799 }
2800
2801 //=======================================================================
2802 // Nested structure conversion
2803 // See FieldMarshaler for details.
2804 //=======================================================================
2805 UINT32 FieldMarshaler_NestedLayoutClass::AlignmentRequirementImpl() const
2806 {
2807     CONTRACTL
2808     {
2809         THROWS;
2810         GC_TRIGGERS;
2811         MODE_ANY;
2812     }
2813     CONTRACTL_END;
2814
2815     return GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2816 }
2817
2818 #if FEATURE_COMINTEROP
2819 MethodDesc* FieldMarshaler_Nullable::GetMethodDescForGenericInstantiation(MethodDesc* pMD) const
2820 {
2821     MethodDesc *pMethodInstantiation;
2822
2823     pMethodInstantiation = MethodDesc::FindOrCreateAssociatedMethodDesc(
2824         pMD,
2825         pMD->GetMethodTable(),
2826         FALSE,
2827         GetMethodTable()->GetInstantiation(),
2828         FALSE,
2829         TRUE);
2830
2831     _ASSERTE(pMethodInstantiation != NULL);
2832
2833     return pMethodInstantiation;
2834 }
2835 #endif //FEATURE_COMINTEROP
2836
2837 #ifndef CROSSGEN_COMPILE
2838
2839 //=======================================================================
2840 // Nested structure conversion
2841 // See FieldMarshaler for details.
2842 //=======================================================================
2843 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const
2844 {
2845     CONTRACTL
2846     {
2847         THROWS;
2848         GC_TRIGGERS;
2849         MODE_COOPERATIVE;
2850         INJECT_FAULT(COMPlusThrowOM());
2851         PRECONDITION(CheckPointer(ppProtectedCLR));
2852         PRECONDITION(CheckPointer(pNative));
2853     }
2854     CONTRACTL_END;
2855
2856     // would be better to detect this at class load time (that have a nested value
2857     // class with no layout) but don't have a way to know
2858     if (! GetMethodTable()->GetLayoutInfo())
2859         COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2860
2861     LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, GetMethodTable(), (BYTE*)pNative, ppCleanupWorkListOnStack);
2862 }
2863
2864
2865 //=======================================================================
2866 // Nested structure conversion
2867 // See FieldMarshaler for details.
2868 //=======================================================================
2869 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const
2870 {
2871     CONTRACTL
2872     {
2873         THROWS;
2874         GC_TRIGGERS;
2875         MODE_COOPERATIVE;
2876         PRECONDITION(CheckPointer(pNative));
2877         PRECONDITION(CheckPointer(ppProtectedCLR));
2878     }
2879     CONTRACTL_END;
2880
2881     // would be better to detect this at class load time (that have a nested value
2882     // class with no layout) but don't have a way to know
2883     if (! GetMethodTable()->GetLayoutInfo())
2884         COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2885
2886     LayoutUpdateCLR( (LPVOID*)ppProtectedCLR,
2887                          startoffset,
2888                          GetMethodTable(),
2889                          (BYTE *)pNative);
2890     
2891
2892 }
2893
2894
2895 //=======================================================================
2896 // Nested structure conversion
2897 // See FieldMarshaler for details.
2898 //=======================================================================
2899 VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) const 
2900 {
2901     CONTRACTL
2902     {
2903         NOTHROW;
2904         GC_TRIGGERS;
2905         MODE_ANY;
2906         PRECONDITION(CheckPointer(pNativeValue));
2907     }
2908     CONTRACTL_END;
2909
2910     LayoutDestroyNative(pNativeValue, GetMethodTable());
2911 }
2912
2913 #endif // CROSSGEN_COMPILE
2914
2915
2916 //=======================================================================
2917 // Nested structure conversion
2918 // See FieldMarshaler for details.
2919 //=======================================================================
2920 UINT32 FieldMarshaler_NestedValueClass::NativeSizeImpl() const
2921 {
2922     CONTRACTL
2923     {
2924         NOTHROW;
2925         GC_NOTRIGGER;
2926         MODE_ANY;
2927     }
2928     CONTRACTL_END;
2929
2930     // this can't be marshalled as native type if no layout, so we allow the 
2931     // native size info to be created if available, but the size will only
2932     // be valid for native, not unions. Marshaller will throw exception if
2933     // try to marshall a value class with no layout
2934     if (GetMethodTable()->HasLayout())
2935         return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2936     
2937     return 0;
2938 }
2939
2940
2941 //=======================================================================
2942 // Nested structure conversion
2943 // See FieldMarshaler for details.
2944 //=======================================================================
2945 UINT32 FieldMarshaler_NestedValueClass::AlignmentRequirementImpl() const
2946 {
2947     CONTRACTL
2948     {
2949         THROWS;
2950         GC_TRIGGERS;
2951         MODE_ANY;
2952     }
2953     CONTRACTL_END;
2954     
2955     // this can't be marshalled as native type if no layout, so we allow the 
2956     // native size info to be created if available, but the alignment will only
2957     // be valid for native, not unions. Marshaller will throw exception if
2958     // try to marshall a value class with no layout
2959     if (GetMethodTable()->HasLayout())
2960     {
2961         UINT32  uAlignmentReq = GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2962         return uAlignmentReq;
2963     }
2964     return 1;
2965 }
2966
2967
2968 #ifndef CROSSGEN_COMPILE
2969
2970 //=======================================================================
2971 // CoTask Uni <--> System.String
2972 // See FieldMarshaler for details.
2973 //=======================================================================
2974 VOID FieldMarshaler_StringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
2975 {
2976     CONTRACTL
2977     {
2978         THROWS;
2979         GC_NOTRIGGER;
2980         MODE_COOPERATIVE;
2981         INJECT_FAULT(COMPlusThrowOM());
2982         PRECONDITION(CheckPointer(pNativeValue));
2983     }
2984     CONTRACTL_END;
2985
2986     STRINGREF pString;
2987     *((OBJECTREF*)&pString) = *pCLRValue;
2988     
2989     if (pString == NULL)
2990     {
2991         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2992     }
2993     else
2994     {
2995         DWORD nc = pString->GetStringLength();
2996         if (nc > MAX_SIZE_FOR_INTEROP)
2997             COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
2998
2999         LPWSTR wsz = (LPWSTR)CoTaskMemAlloc( (nc + 1) * sizeof(WCHAR) );
3000         if (!wsz)
3001             COMPlusThrowOM();
3002
3003         memcpyNoGCRefs(wsz, pString->GetBuffer(), nc*sizeof(WCHAR));
3004         wsz[nc] = W('\0');
3005         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, wsz);
3006     }
3007 }
3008
3009
3010 //=======================================================================
3011 // CoTask Uni <--> System.String
3012 // See FieldMarshaler for details.
3013 //=======================================================================
3014 VOID FieldMarshaler_StringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3015 {
3016     CONTRACTL
3017     {
3018         THROWS;
3019         GC_TRIGGERS;
3020         MODE_COOPERATIVE;
3021         PRECONDITION(CheckPointer(pNativeValue));
3022         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3023     }
3024     CONTRACTL_END;
3025
3026     STRINGREF pString;
3027     LPCWSTR wsz = (LPCWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3028     
3029     if (!wsz)
3030         pString = NULL;
3031     else
3032     {
3033         SIZE_T length = wcslen(wsz);
3034         if (length > MAX_SIZE_FOR_INTEROP)
3035             COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3036
3037         pString = StringObject::NewString(wsz, (DWORD)length);
3038     }
3039     
3040     *((STRINGREF*)ppProtectedCLRValue) = pString;
3041 }
3042
3043
3044 //=======================================================================
3045 // CoTask Uni <--> System.String
3046 // See FieldMarshaler for details.
3047 //=======================================================================
3048 VOID FieldMarshaler_StringUni::DestroyNativeImpl(LPVOID pNativeValue) const 
3049 {
3050     CONTRACTL
3051     {
3052         NOTHROW;
3053         GC_NOTRIGGER;
3054         MODE_ANY;
3055         PRECONDITION(CheckPointer(pNativeValue));        
3056     }
3057     CONTRACTL_END;
3058     
3059     LPWSTR wsz = (LPWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3060     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3061     if (wsz)
3062         CoTaskMemFree(wsz);
3063 }
3064
3065
3066
3067 //=======================================================================
3068 // CoTask Ansi <--> System.String
3069 // See FieldMarshaler for details.
3070 //=======================================================================
3071 VOID FieldMarshaler_StringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3072 {
3073     CONTRACTL
3074     {
3075         THROWS;
3076         GC_TRIGGERS;
3077         MODE_COOPERATIVE;
3078         INJECT_FAULT(COMPlusThrowOM());
3079         PRECONDITION(CheckPointer(pNativeValue));
3080     }
3081     CONTRACTL_END;
3082
3083     STRINGREF pString;
3084     *((OBJECTREF*)&pString) = *pCLRValue;
3085     
3086     if (pString == NULL)
3087     {
3088         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3089     }
3090     else
3091     {
3092         DWORD nc = pString->GetStringLength();
3093         if (nc > MAX_SIZE_FOR_INTEROP)
3094             COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3095  
3096         LPSTR sz = (LPSTR)CoTaskMemAlloc( (nc + 1) * 2 /* 2 for MBCS */ );
3097         if (!sz)
3098             COMPlusThrowOM(); 
3099
3100         int nbytes = InternalWideToAnsi(pString->GetBuffer(),
3101                                         nc,
3102                                         sz,
3103                                         nc*2,
3104                                         m_BestFitMap,
3105                                         m_ThrowOnUnmappableChar);
3106         sz[nbytes] = '\0';
3107
3108         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, sz);
3109      }
3110 }
3111
3112
3113 //=======================================================================
3114 // CoTask Ansi <--> System.String
3115 // See FieldMarshaler for details.
3116 //=======================================================================
3117 VOID FieldMarshaler_StringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3118 {
3119     CONTRACTL
3120     {
3121         THROWS;
3122         GC_TRIGGERS;
3123         MODE_COOPERATIVE;
3124         INJECT_FAULT(COMPlusThrowOM());
3125         PRECONDITION(CheckPointer(pNativeValue));
3126         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3127     }
3128     CONTRACTL_END;
3129
3130     STRINGREF pString = NULL;
3131     LPCSTR sz = (LPCSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3132     if (!sz) 
3133         pString = NULL;
3134     else 
3135     {
3136         MAKE_WIDEPTR_FROMANSI(wsztemp, sz);
3137         pString = StringObject::NewString(wsztemp, __lwsztemp - 1);
3138     }
3139     
3140     *((STRINGREF*)ppProtectedCLRValue) = pString;
3141 }
3142
3143
3144 //=======================================================================
3145 // CoTask Ansi <--> System.String
3146 // See FieldMarshaler for details.
3147 //=======================================================================
3148 VOID FieldMarshaler_StringAnsi::DestroyNativeImpl(LPVOID pNativeValue) const 
3149 {
3150     CONTRACTL
3151     {
3152         NOTHROW;
3153         GC_NOTRIGGER;
3154         MODE_ANY;
3155         PRECONDITION(CheckPointer(pNativeValue));        
3156     }
3157     CONTRACTL_END;
3158     
3159     LPSTR sz = (LPSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3160     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3161     if (sz)
3162         CoTaskMemFree(sz);
3163 }
3164
3165 //=======================================================================
3166 // CoTask Utf8 <--> System.String
3167 // See FieldMarshaler for details.
3168 //=======================================================================
3169 VOID FieldMarshaler_StringUtf8::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3170 {
3171     CONTRACTL
3172     {
3173         THROWS;
3174         GC_TRIGGERS;
3175         MODE_COOPERATIVE;
3176         INJECT_FAULT(COMPlusThrowOM());
3177         PRECONDITION(CheckPointer(pNativeValue));
3178     }
3179     CONTRACTL_END;
3180
3181     STRINGREF pString = (STRINGREF)(*pCLRValue);
3182     if (pString == NULL)
3183     {
3184         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3185     }
3186     else
3187     {
3188         DWORD nc = pString->GetStringLength();
3189         if (nc > MAX_SIZE_FOR_INTEROP)
3190             COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3191
3192         // Characters would be # of characters + 1 in case left over high surrogate is ?
3193         // Max 3 bytes per char for basic multi-lingual plane.
3194         nc = (nc + 1) * MAX_UTF8_CHAR_SIZE;
3195         // +1 for '\0'
3196         LPUTF8  lpBuffer = (LPUTF8)CoTaskMemAlloc(nc + 1);
3197         if (!lpBuffer)
3198         {
3199             COMPlusThrowOM();
3200         }
3201
3202         // UTF8Marshaler.ConvertToNative
3203         MethodDescCallSite convertToNative(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE);
3204         
3205         ARG_SLOT args[] =
3206         {
3207             ((ARG_SLOT)(CLR_I4)0),
3208             ObjToArgSlot(*pCLRValue),
3209             PtrToArgSlot(lpBuffer)
3210         };
3211         convertToNative.Call(args);
3212         MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, lpBuffer);
3213     }
3214 }
3215
3216
3217 //=======================================================================
3218 // CoTask Utf8 <--> System.String
3219 // See FieldMarshaler for details.
3220 //=======================================================================
3221 VOID FieldMarshaler_StringUtf8::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3222 {
3223     CONTRACTL
3224     {
3225         THROWS;
3226         GC_TRIGGERS;
3227         MODE_COOPERATIVE;
3228         INJECT_FAULT(COMPlusThrowOM());
3229         PRECONDITION(CheckPointer(pNativeValue));
3230         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3231     }
3232     CONTRACTL_END;
3233
3234     STRINGREF pString = NULL;
3235     LPCUTF8  sz = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3236     if (!sz)
3237     {
3238         pString = NULL;
3239     }
3240     else
3241     {
3242         MethodDescCallSite convertToManaged(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED);
3243         ARG_SLOT args[] =
3244         {
3245             PtrToArgSlot(pNativeValue),
3246         };
3247         pString = convertToManaged.Call_RetSTRINGREF(args);
3248     }
3249     *((STRINGREF*)ppProtectedCLRValue) = pString;
3250 }
3251
3252 //=======================================================================
3253 // CoTask Utf8 <--> System.String
3254 // See FieldMarshaler for details.
3255 //=======================================================================
3256 VOID FieldMarshaler_StringUtf8::DestroyNativeImpl(LPVOID pNativeValue) const
3257 {
3258     CONTRACTL
3259     {
3260         NOTHROW;
3261         GC_NOTRIGGER;
3262         MODE_ANY;
3263         PRECONDITION(CheckPointer(pNativeValue));
3264     }
3265     CONTRACTL_END;
3266
3267     LPCUTF8 lpBuffer = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3268     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3269     if (lpBuffer)
3270         CoTaskMemFree((LPVOID)lpBuffer);
3271 }
3272
3273 //=======================================================================
3274 // FixedString <--> System.String
3275 // See FieldMarshaler for details.
3276 //=======================================================================
3277 VOID FieldMarshaler_FixedStringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3278 {
3279     CONTRACTL
3280     {
3281         NOTHROW;
3282         GC_NOTRIGGER;
3283         MODE_COOPERATIVE;
3284         PRECONDITION(CheckPointer(pNativeValue));
3285     }
3286     CONTRACTL_END;
3287
3288     STRINGREF pString;
3289     *((OBJECTREF*)&pString) = *pCLRValue;
3290     
3291     if (pString == NULL)
3292     {
3293         MAYBE_UNALIGNED_WRITE(pNativeValue, 16, W('\0'));
3294     }
3295     else
3296     {
3297         DWORD nc = pString->GetStringLength();
3298         if (nc >= m_numchar)
3299             nc = m_numchar - 1;
3300
3301         memcpyNoGCRefs(pNativeValue, pString->GetBuffer(), nc*sizeof(WCHAR));
3302         MAYBE_UNALIGNED_WRITE(&(((WCHAR*)pNativeValue)[nc]), 16, W('\0'));
3303     }
3304
3305 }
3306
3307
3308 //=======================================================================
3309 // FixedString <--> System.String
3310 // See FieldMarshaler for details.
3311 //=======================================================================
3312 VOID FieldMarshaler_FixedStringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3313 {
3314     CONTRACTL
3315     {
3316         THROWS;
3317         GC_TRIGGERS;
3318         MODE_COOPERATIVE;
3319         PRECONDITION(CheckPointer(pNativeValue));
3320         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3321     }
3322     CONTRACTL_END;
3323
3324     STRINGREF pString;
3325     SIZE_T    ncActual = wcsnlen((const WCHAR *)pNativeValue, m_numchar);
3326
3327     if (!FitsIn<int>(ncActual))
3328         COMPlusThrowHR(COR_E_OVERFLOW);
3329
3330     pString = StringObject::NewString((const WCHAR *)pNativeValue, (int)ncActual);
3331     *((STRINGREF*)ppProtectedCLRValue) = pString;
3332 }
3333
3334
3335
3336
3337
3338
3339
3340 //=======================================================================
3341 // FixedString <--> System.String
3342 // See FieldMarshaler for details.
3343 //=======================================================================
3344 VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3345 {
3346     CONTRACTL
3347     {
3348         THROWS;
3349         GC_TRIGGERS;
3350         MODE_COOPERATIVE;
3351         PRECONDITION(CheckPointer(pNativeValue));
3352     }
3353     CONTRACTL_END;
3354
3355     STRINGREF pString;
3356     *((OBJECTREF*)&pString) = *pCLRValue;
3357     
3358     if (pString == NULL)
3359         *((CHAR*)pNativeValue) = W('\0');
3360     else
3361     {
3362         DWORD nc = pString->GetStringLength();
3363         if (nc >= m_numchar)
3364             nc = m_numchar - 1;
3365
3366         int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
3367             nc,
3368             (CHAR*)pNativeValue,
3369             m_numchar,
3370             m_BestFitMap,
3371             m_ThrowOnUnmappableChar);
3372
3373         // Handle the case where SizeConst == Number of bytes.For single byte chars 
3374         // this will never be the case since nc >= m_numchar check will truncate the last 
3375         // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
3376         // gives number of characters but not the actual number of bytes. For such cases need to make 
3377         // sure that we dont write one past the buffer.
3378         if (cbwritten == (int) m_numchar)
3379             --cbwritten;
3380
3381         ((CHAR*)pNativeValue)[cbwritten] = '\0';
3382     }
3383 }
3384
3385
3386 //=======================================================================
3387 // FixedString <--> System.String
3388 // See FieldMarshaler for details.
3389 //=======================================================================
3390 VOID FieldMarshaler_FixedStringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3391 {
3392     CONTRACTL
3393     {
3394         THROWS;
3395         GC_TRIGGERS;
3396         MODE_COOPERATIVE;
3397         INJECT_FAULT(COMPlusThrowOM());
3398         PRECONDITION(CheckPointer(pNativeValue));
3399         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3400
3401         // should not have slipped past the metadata
3402         PRECONDITION(m_numchar != 0);
3403     }
3404     CONTRACTL_END;
3405
3406     STRINGREF pString;
3407     if (m_numchar == 0)
3408     {
3409         // but if it does, better to throw an exception tardily rather than
3410         // allow a memory corrupt.
3411         COMPlusThrow(kMarshalDirectiveException);
3412     }
3413
3414     UINT32 allocSize = m_numchar + 2;
3415     if (allocSize < m_numchar)
3416         ThrowOutOfMemory();
3417     
3418     LPSTR tempbuf = (LPSTR)(_alloca((size_t)allocSize));
3419     if (!tempbuf)
3420         ThrowOutOfMemory();
3421
3422     memcpyNoGCRefs(tempbuf, pNativeValue, m_numchar);
3423     tempbuf[m_numchar-1] = '\0';
3424     tempbuf[m_numchar] = '\0';
3425     tempbuf[m_numchar+1] = '\0';
3426
3427     allocSize = m_numchar * sizeof(WCHAR);
3428     if (allocSize < m_numchar)
3429         ThrowOutOfMemory();
3430     
3431     LPWSTR    wsztemp = (LPWSTR)_alloca( (size_t)allocSize );
3432     int ncwritten = MultiByteToWideChar(CP_ACP,
3433                                         MB_PRECOMPOSED,
3434                                         tempbuf,
3435                                         -1,  // # of CHAR's in inbuffer
3436                                         wsztemp,
3437                                         m_numchar                       // size (in WCHAR) of outbuffer
3438                                         );
3439
3440     if (!ncwritten)
3441     {
3442         // intentionally not throwing for MB2WC failure. We don't always know
3443         // whether to expect a valid string in the buffer and we don't want
3444         // to throw exceptions randomly.
3445         ncwritten++;
3446     }
3447
3448     pString = StringObject::NewString((const WCHAR *)wsztemp, ncwritten-1);
3449     *((STRINGREF*)ppProtectedCLRValue) = pString;
3450 }
3451
3452
3453 //=======================================================================
3454 // CHAR[] <--> char[]
3455 // See FieldMarshaler for details.
3456 //=======================================================================
3457 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3458 {
3459     CONTRACTL
3460     {
3461         THROWS;
3462         GC_TRIGGERS;
3463         MODE_COOPERATIVE;
3464         INJECT_FAULT(COMPlusThrowOM());
3465         PRECONDITION(CheckPointer(pNativeValue));
3466     }
3467     CONTRACTL_END;
3468
3469     I2ARRAYREF pArray;
3470     *((OBJECTREF*)&pArray) = *pCLRValue;
3471
3472     if (pArray == NULL)
3473         FillMemory(pNativeValue, m_numElems * sizeof(CHAR), 0);
3474     else
3475     {
3476         if (pArray->GetNumComponents() < m_numElems)
3477             COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3478         else
3479         {
3480             InternalWideToAnsi((const WCHAR*) pArray->GetDataPtr(),
3481                                m_numElems,
3482                               (CHAR*)pNativeValue,
3483                                m_numElems * sizeof(CHAR),
3484                                m_BestFitMap,
3485                                m_ThrowOnUnmappableChar);
3486         }
3487     }
3488 }
3489
3490
3491 //=======================================================================
3492 // CHAR[] <--> char[]
3493 // See FieldMarshaler for details.
3494 //=======================================================================
3495 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3496 {
3497     CONTRACTL
3498     {
3499         THROWS;
3500         GC_TRIGGERS;
3501         MODE_COOPERATIVE;
3502         INJECT_FAULT(COMPlusThrowOM());
3503         PRECONDITION(CheckPointer(pNativeValue));
3504         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3505     }
3506     CONTRACTL_END;
3507
3508     *ppProtectedCLRValue = AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, m_numElems);
3509
3510     MultiByteToWideChar(CP_ACP,
3511                         MB_PRECOMPOSED,
3512                         (const CHAR *)pNativeValue,
3513                         m_numElems * sizeof(CHAR), // size, in bytes, of in buffer
3514                         (WCHAR*) ((*((I2ARRAYREF*)ppProtectedCLRValue))->GetDirectPointerToNonObjectElements()),
3515                         m_numElems);               // size, in WCHAR's of outbuffer                       
3516 }
3517
3518 #endif // CROSSGEN_COMPILE
3519
3520
3521 //=======================================================================
3522 // Embedded array
3523 // See FieldMarshaler for details.
3524 //=======================================================================
3525 FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
3526 : m_numElems(numElems)
3527 , m_vt(vt)
3528 , m_BestFitMap(FALSE)
3529 , m_ThrowOnUnmappableChar(FALSE)
3530 {
3531     CONTRACTL
3532     {
3533         THROWS;
3534         GC_TRIGGERS;
3535         MODE_ANY;
3536         PRECONDITION(CheckPointer(pElementMT));
3537         PRECONDITION(vt != VTHACK_ANSICHAR);        // This must be handled by the FixedCharArrayAnsi marshaler.
3538     }
3539     CONTRACTL_END;
3540
3541     // Only attempt to read the best fit mapping attribute if required to minimize
3542     // custom attribute accesses.
3543     if (vt == VT_LPSTR || vt == VT_RECORD)
3544     {
3545         BOOL BestFitMap = FALSE;
3546         BOOL ThrowOnUnmappableChar = FALSE;
3547         ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar);      
3548         m_BestFitMap = !!BestFitMap;
3549         m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar;
3550     }
3551
3552     m_arrayType.SetValue(ClassLoader::LoadArrayTypeThrowing(TypeHandle(pElementMT),
3553                                                      ELEMENT_TYPE_SZARRAY,
3554                                                      0,
3555                                                      ClassLoader::LoadTypes,
3556                                                      pElementMT->GetLoadLevel()));
3557 }
3558
3559
3560 #ifndef CROSSGEN_COMPILE
3561
3562 //=======================================================================
3563 // Embedded array
3564 // See FieldMarshaler for details.
3565 //=======================================================================
3566 VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3567 {
3568     CONTRACTL
3569     {
3570         THROWS;
3571         GC_TRIGGERS;
3572         MODE_COOPERATIVE;
3573         PRECONDITION(CheckPointer(pNativeValue));
3574     }
3575     CONTRACTL_END;
3576
3577     if (*pCLRValue == NULL)
3578     {
3579         FillMemory(pNativeValue, NativeSize(), 0);
3580     }
3581     else
3582     {
3583         // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
3584         if ((*pCLRValue)->GetNumComponents() < m_numElems)
3585             COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3586   
3587         // Marshal the contents from the managed array to the native array.
3588         const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);  
3589         if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
3590         {
3591             memcpyNoGCRefs(pNativeValue, (*(BASEARRAYREF*)pCLRValue)->GetDataPtr(), NativeSize());
3592         }
3593         else
3594         {
3595             MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3596
3597             // We never operate on an uninitialized native layout here, we have zero'ed it if needed.
3598             // Therefore fOleArrayIsValid is always TRUE.
3599             pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
3600         }
3601     }
3602 }
3603
3604
3605 //=======================================================================
3606 // Embedded array
3607 // See FieldMarshaler for details.
3608 //=======================================================================
3609 VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3610 {
3611     CONTRACTL
3612     {
3613         THROWS;
3614         GC_TRIGGERS;
3615         MODE_COOPERATIVE;
3616         INJECT_FAULT(COMPlusThrowOM());
3617         PRECONDITION(CheckPointer(pNativeValue));
3618         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3619     }
3620     CONTRACTL_END;
3621
3622     // Allocate the value class array.
3623     *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1);
3624
3625     // Marshal the contents from the native array to the managed array.
3626     const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);        
3627     if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
3628     {
3629         memcpyNoGCRefs((*(BASEARRAYREF*)ppProtectedCLRValue)->GetDataPtr(), pNativeValue, NativeSize());
3630     }
3631     else
3632     {
3633         MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3634         pMarshaler->OleToComArray((VOID *)pNativeValue, (BASEARRAYREF*)ppProtectedCLRValue, pElementMT);
3635     }
3636 }
3637
3638 //=======================================================================
3639 // Embedded array
3640 // See FieldMarshaler for details.
3641 //=======================================================================
3642 VOID FieldMarshaler_FixedArray::DestroyNativeImpl(LPVOID pNativeValue) const
3643 {
3644     CONTRACTL
3645     {
3646         NOTHROW;
3647         GC_TRIGGERS;
3648         MODE_ANY;
3649         INJECT_FAULT(COMPlusThrowOM());
3650         PRECONDITION(CheckPointer(pNativeValue));
3651     }
3652     CONTRACTL_END;
3653
3654     const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, FALSE);
3655
3656     if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
3657     {
3658         MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3659         pMarshaler->ClearOleArray(pNativeValue, m_numElems, pElementMT);
3660     }
3661 }
3662
3663 #endif // CROSSGEN_COMPILE
3664
3665
3666 //=======================================================================
3667 // Embedded array
3668 // See FieldMarshaler for details.
3669 //=======================================================================
3670 UINT32 FieldMarshaler_FixedArray::AlignmentRequirementImpl() const
3671 {
3672     WRAPPER_NO_CONTRACT;
3673
3674     UINT32 alignment = 0;
3675     TypeHandle elementType = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle();
3676
3677     switch (m_vt)
3678     {
3679         case VT_DECIMAL:
3680             alignment = 8;
3681             break;
3682
3683         case VT_VARIANT:
3684             alignment = 8;
3685             break;
3686
3687         case VT_RECORD:
3688             alignment = elementType.GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();    
3689             break;
3690
3691         default:
3692             alignment = OleVariant::GetElementSizeForVarType(m_vt, elementType.GetMethodTable());
3693             break;
3694     }
3695
3696     return alignment;
3697 }
3698   
3699 #ifndef CROSSGEN_COMPILE
3700
3701 #ifdef FEATURE_CLASSIC_COMINTEROP
3702 //=======================================================================
3703 // SafeArray
3704 // See FieldMarshaler for details.
3705 //=======================================================================
3706 VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3707 {
3708     CONTRACTL
3709     {
3710         THROWS;
3711         GC_TRIGGERS;
3712         MODE_COOPERATIVE;
3713         PRECONDITION(CheckPointer(pNativeValue));
3714     }
3715     CONTRACTL_END;
3716
3717     BASEARRAYREF pArray;
3718     *((OBJECTREF*)&pArray) = *pCLRValue;
3719     if ((pArray == NULL) || (OBJECTREFToObject(pArray) == NULL))
3720     {
3721         FillMemory(pNativeValue, sizeof(LPSAFEARRAY*), 0);
3722         return;
3723     }
3724     
3725     LPSAFEARRAY* pSafeArray;
3726     pSafeArray = (LPSAFEARRAY*)pNativeValue;
3727
3728     VARTYPE vt = m_vt;
3729     MethodTable* pMT = m_pMT.GetValueMaybeNull();
3730
3731     GCPROTECT_BEGIN(pArray)
3732     {
3733         if (vt == VT_EMPTY)
3734             vt = OleVariant::GetElementVarTypeForArrayRef(pArray);
3735
3736         if (!pMT)
3737             pMT = OleVariant::GetArrayElementTypeWrapperAware(&pArray).GetMethodTable();
3738
3739         // OleVariant calls throw on error.
3740         *pSafeArray = OleVariant::CreateSafeArrayForArrayRef(&pArray, vt, pMT);
3741         OleVariant::MarshalSafeArrayForArrayRef(&pArray, *pSafeArray, vt, pMT);
3742     }
3743     GCPROTECT_END();
3744 }
3745
3746
3747 //=======================================================================
3748 // SafeArray
3749 // See FieldMarshaler for details.
3750 //=======================================================================
3751 VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3752 {
3753     CONTRACTL
3754     {
3755         THROWS;
3756         GC_TRIGGERS;
3757         MODE_COOPERATIVE;
3758         INJECT_FAULT(COMPlusThrowOM());
3759         PRECONDITION(CheckPointer(pNativeValue));
3760         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3761     }
3762     CONTRACTL_END;
3763
3764     LPSAFEARRAY* pSafeArray;
3765     pSafeArray = (LPSAFEARRAY*)pNativeValue;
3766
3767     if ((pSafeArray == NULL) || (*pSafeArray == NULL))
3768     {
3769         *ppProtectedCLRValue = NULL;
3770         return;
3771     }
3772
3773     VARTYPE vt = m_vt;
3774     MethodTable* pMT = m_pMT.GetValueMaybeNull();
3775
3776     // If we have an empty vartype, get it from the safearray vartype
3777     if (vt == VT_EMPTY)
3778     {
3779         if (FAILED(ClrSafeArrayGetVartype(*pSafeArray, &vt)))
3780             COMPlusThrow(kArgumentException, IDS_EE_INVALID_SAFEARRAY);
3781     }
3782
3783     // Get the method table if we need to.
3784     if ((vt == VT_RECORD) && (!pMT))
3785         pMT = OleVariant::GetElementTypeForRecordSafeArray(*pSafeArray).GetMethodTable();
3786
3787     // If we have a single dimension safearray, it will be converted into a SZArray.
3788     // SZArray must have a lower bound of zero.
3789     LONG LowerBound = -1;
3790     UINT Dimensions = SafeArrayGetDim( (SAFEARRAY*)*pSafeArray );    
3791
3792     if (Dimensions == 1)
3793     {
3794         HRESULT hr = SafeArrayGetLBound((SAFEARRAY*)*pSafeArray, 1, &LowerBound);
3795         if ( FAILED(hr) || LowerBound != 0)
3796         COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
3797     }
3798     
3799     // OleVariant calls throw on error.
3800     *ppProtectedCLRValue = OleVariant::CreateArrayRefForSafeArray(*pSafeArray, vt, pMT);
3801     OleVariant::MarshalArrayRefForSafeArray(*pSafeArray, (BASEARRAYREF*)ppProtectedCLRValue, vt, pMT);
3802 }
3803
3804
3805 //=======================================================================
3806 // SafeArray
3807 // See FieldMarshaler for details.
3808 //=======================================================================
3809 VOID FieldMarshaler_SafeArray::DestroyNativeImpl(LPVOID pNativeValue) const 
3810 {
3811     CONTRACTL
3812     {
3813         NOTHROW;
3814         GC_TRIGGERS;
3815         MODE_ANY;
3816         PRECONDITION(CheckPointer(pNativeValue));
3817     }
3818     CONTRACTL_END;
3819
3820     HRESULT hr;
3821     GCX_PREEMP();
3822
3823     LPSAFEARRAY psa = (LPSAFEARRAY)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3824     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3825     
3826     if (psa)
3827     {
3828         _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
3829         // SafeArray has been created, which means oleaut32 should have been loaded.
3830         // Delay load will not fail.
3831         CONTRACT_VIOLATION(ThrowsViolation);
3832         hr = SafeArrayDestroy(psa);
3833         _ASSERTE(!FAILED(hr));        
3834     }
3835 }
3836 #endif //FEATURE_CLASSIC_COMINTEROP
3837
3838
3839 //=======================================================================
3840 // function ptr <--> Delegate
3841 // See FieldMarshaler for details.
3842 //=======================================================================
3843 VOID FieldMarshaler_Delegate::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3844 {
3845     CONTRACTL
3846     {
3847         THROWS;
3848         GC_TRIGGERS;
3849         MODE_COOPERATIVE;
3850         PRECONDITION(CheckPointer(pNativeValue));
3851     }
3852     CONTRACTL_END;
3853
3854     LPVOID fnPtr = COMDelegate::ConvertToCallback(*pCLRValue);
3855     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, fnPtr);
3856 }
3857
3858
3859 //=======================================================================
3860 // function ptr <--> Delegate
3861 // See FieldMarshaler for details.
3862 //=======================================================================
3863 VOID FieldMarshaler_Delegate::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3864 {
3865     CONTRACTL
3866     {
3867         THROWS;
3868         GC_TRIGGERS;
3869         MODE_COOPERATIVE;
3870         PRECONDITION(CheckPointer(pNativeValue));
3871         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3872     }
3873     CONTRACTL_END;
3874
3875     *ppProtectedCLRValue = COMDelegate::ConvertToDelegate((LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR), GetMethodTable());
3876 }
3877
3878
3879 //=======================================================================
3880 // SafeHandle <--> Handle
3881 // See FieldMarshaler for details.
3882 //=======================================================================
3883 VOID FieldMarshaler_SafeHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3884 {
3885     CONTRACTL
3886     {
3887         THROWS;
3888         GC_TRIGGERS;
3889         MODE_COOPERATIVE;
3890         PRECONDITION(CheckPointer(pNativeValue));
3891         PRECONDITION(CheckPointer(ppCleanupWorkListOnStack, NULL_OK));
3892     }
3893     CONTRACTL_END;
3894
3895     SAFEHANDLE *pSafeHandleObj = ((SAFEHANDLE *)pCLRValue);
3896
3897     // A cleanup list MUST be specified in order for us to be able to marshal
3898     // the SafeHandle.
3899     if (ppCleanupWorkListOnStack == NULL)
3900         COMPlusThrow(kInvalidOperationException, IDS_EE_SH_FIELD_INVALID_OPERATION);
3901
3902     if (*pSafeHandleObj == NULL)
3903         COMPlusThrow(kArgumentNullException, W("ArgumentNull_SafeHandle"));
3904
3905     // Call StubHelpers.AddToCleanupList to AddRef and schedule Release on this SafeHandle
3906     // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
3907     MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST);
3908
3909     ARG_SLOT args[] =
3910     {
3911         (ARG_SLOT)ppCleanupWorkListOnStack,
3912         ObjToArgSlot(*pSafeHandleObj)
3913     };
3914
3915     LPVOID handle = AddToCleanupList.Call_RetLPVOID(args);
3916
3917     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3918 }
3919
3920
3921 //=======================================================================
3922 // SafeHandle <--> Handle
3923 // See FieldMarshaler for details.
3924 //=======================================================================
3925 VOID FieldMarshaler_SafeHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3926 {
3927     CONTRACTL
3928     {
3929         THROWS;
3930         GC_TRIGGERS;
3931         MODE_COOPERATIVE;
3932         PRECONDITION(CheckPointer(pNativeValue));
3933         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3934         PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
3935     }
3936     CONTRACTL_END;
3937
3938     // Since we dissallow marshaling SafeHandle fields from unmanaged to managed, check
3939     // to see if this handle was obtained from a SafeHandle and if it was that the
3940     // handle value hasn't changed.
3941     SAFEHANDLE *pSafeHandleObj = (SAFEHANDLE *)ppProtectedOldCLRValue;
3942     if (!*pSafeHandleObj || (*pSafeHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
3943         COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_SAFEHANDLE_FIELD);
3944
3945     // Now that we know the handle hasn't changed we just copy set the new SafeHandle
3946     // to the old one.
3947     *ppProtectedCLRValue = *ppProtectedOldCLRValue;
3948 }
3949
3950
3951 //=======================================================================
3952 // CriticalHandle <--> Handle
3953 // See FieldMarshaler for details.
3954 //=======================================================================
3955 VOID FieldMarshaler_CriticalHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
3956 {
3957     CONTRACTL
3958     {
3959         THROWS;
3960         GC_TRIGGERS;
3961         MODE_COOPERATIVE;
3962         PRECONDITION(CheckPointer(pNativeValue));
3963     }
3964     CONTRACTL_END;
3965
3966     LPVOID handle = ((CRITICALHANDLE)*pCLRValue)->GetHandle();
3967     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3968 }
3969
3970
3971 //=======================================================================
3972 // CriticalHandle <--> Handle
3973 // See FieldMarshaler for details.
3974 //=======================================================================
3975 VOID FieldMarshaler_CriticalHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
3976 {
3977     CONTRACTL
3978     {
3979         THROWS;
3980         GC_TRIGGERS;
3981         MODE_COOPERATIVE;
3982         PRECONDITION(CheckPointer(pNativeValue));
3983         PRECONDITION(CheckPointer(ppProtectedCLRValue));
3984         PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
3985     }
3986     CONTRACTL_END;
3987
3988     // Since we dissallow marshaling CriticalHandle fields from unmanaged to managed, check
3989     // to see if this handle was obtained from a CriticalHandle and if it was that the
3990     // handle value hasn't changed.
3991     CRITICALHANDLE *pCriticalHandleObj = (CRITICALHANDLE *)ppProtectedOldCLRValue;
3992     if (!*pCriticalHandleObj || (*pCriticalHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
3993         COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_CRITICALHANDLE_FIELD);
3994
3995     // Now that we know the handle hasn't changed we just copy set the new CriticalHandle
3996     // to the old one.
3997     *ppProtectedCLRValue = *ppProtectedOldCLRValue;
3998 }
3999
4000 #ifdef FEATURE_COMINTEROP
4001
4002 //=======================================================================
4003 // COM IP <--> interface
4004 // See FieldMarshaler for details.
4005 //=======================================================================
4006 VOID FieldMarshaler_Interface::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
4007 {
4008     CONTRACTL
4009     {
4010         THROWS;
4011         GC_TRIGGERS;
4012         MODE_COOPERATIVE;
4013         PRECONDITION(CheckPointer(pNativeValue));
4014     }
4015     CONTRACTL_END;
4016
4017     IUnknown *pUnk = NULL;
4018
4019     if (!m_pItfMT.IsNull())
4020     {
4021         pUnk = GetComIPFromObjectRef(pCLRValue, GetInterfaceMethodTable());
4022     }
4023     else if (!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF))
4024     {
4025         pUnk = GetComIPFromObjectRef(pCLRValue, GetMethodTable());
4026     }
4027     else
4028     {
4029         ComIpType ReqIpType = !!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? ComIpType_Dispatch : ComIpType_Unknown;
4030         pUnk = GetComIPFromObjectRef(pCLRValue, ReqIpType, NULL);
4031     }
4032
4033     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pUnk);    
4034 }
4035
4036
4037 //=======================================================================
4038 // COM IP <--> interface
4039 // See FieldMarshaler for details.
4040 //=======================================================================
4041 VOID FieldMarshaler_Interface::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
4042 {
4043     CONTRACTL
4044     {
4045         THROWS;
4046         GC_TRIGGERS;
4047         MODE_COOPERATIVE;
4048         PRECONDITION(CheckPointer(pNativeValue));
4049         PRECONDITION(CheckPointer(ppProtectedCLRValue));
4050         PRECONDITION(IsProtectedByGCFrame(ppProtectedCLRValue));
4051     }
4052     CONTRACTL_END;
4053
4054     IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4055
4056     MethodTable *pItfMT = GetInterfaceMethodTable();
4057     if (pItfMT != NULL && !pItfMT->IsInterface())
4058         pItfMT = NULL;
4059
4060     GetObjectRefFromComIP(
4061         ppProtectedCLRValue,                                    // Created object
4062         pUnk,                                                   // Interface pointer
4063         GetMethodTable(),                                       // Class MT
4064         pItfMT,                                                 // Interface MT
4065         (m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT) // Flags
4066     );
4067 }
4068
4069
4070 //=======================================================================
4071 // COM IP <--> interface
4072 // See FieldMarshaler for details.
4073 //=======================================================================
4074 VOID FieldMarshaler_Interface::DestroyNativeImpl(LPVOID pNativeValue) const 
4075 {
4076     CONTRACTL
4077     {
4078         NOTHROW;
4079         GC_TRIGGERS;
4080         MODE_ANY;
4081         PRECONDITION(CheckPointer(pNativeValue));
4082     }
4083     CONTRACTL_END;
4084
4085     IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4086     MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
4087
4088     if (pUnk != NULL)
4089     {
4090         ULONG cbRef = SafeRelease(pUnk);
4091         LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
4092     }
4093 }
4094
4095 #endif // FEATURE_COMINTEROP
4096
4097
4098 //=======================================================================
4099 // See FieldMarshaler for details.
4100 //=======================================================================
4101 VOID FieldMarshaler_Date::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4102 {
4103     CONTRACTL
4104     {
4105         THROWS;
4106         GC_TRIGGERS;
4107         MODE_COOPERATIVE;
4108         PRECONDITION(CheckPointer(pCLR));
4109         PRECONDITION(CheckPointer(pNative));
4110     }
4111     CONTRACTL_END;
4112
4113     // <TODO> Handle unaligned native fields </TODO>
4114     *((DATE*)pNative) =  COMDateTime::TicksToDoubleDate(*((INT64*)pCLR));
4115 }
4116
4117
4118 //=======================================================================
4119 // See FieldMarshaler for details.
4120 //=======================================================================
4121 VOID FieldMarshaler_Date::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4122 {
4123     CONTRACTL
4124     {
4125         THROWS;
4126         GC_TRIGGERS;
4127         MODE_COOPERATIVE;
4128         PRECONDITION(CheckPointer(pNative));
4129         PRECONDITION(CheckPointer(pCLR));
4130     }
4131     CONTRACTL_END;
4132
4133     // <TODO> Handle unaligned native fields </TODO>
4134     *((INT64*)pCLR) = COMDateTime::DoubleDateToTicks(*((DATE*)pNative));
4135 }
4136
4137
4138 #ifdef FEATURE_COMINTEROP
4139
4140 //=======================================================================
4141 // See FieldMarshaler for details.
4142 //=======================================================================
4143 VOID FieldMarshaler_Currency::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4144 {
4145     CONTRACTL
4146     {
4147         THROWS;
4148         GC_TRIGGERS;
4149         MODE_ANY;
4150         PRECONDITION(CheckPointer(pCLR));
4151         PRECONDITION(CheckPointer(pNative));
4152     }
4153     CONTRACTL_END;
4154
4155     // no need to switch to preemptive mode because it's very primitive operaion, doesn't take 
4156     // long and is guaranteed not to call 3rd party code. 
4157     // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4158     HRESULT hr = VarCyFromDec( (DECIMAL *)pCLR, (CURRENCY*)pNative);
4159     if (FAILED(hr))
4160         COMPlusThrowHR(hr);
4161
4162 }
4163
4164
4165 //=======================================================================
4166 // See FieldMarshaler for details.
4167 //=======================================================================
4168 VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4169 {
4170     CONTRACTL
4171     {
4172         THROWS;
4173         GC_TRIGGERS;
4174         MODE_ANY;
4175         PRECONDITION(CheckPointer(pNative));
4176         PRECONDITION(CheckPointer(pCLR));
4177     }
4178     CONTRACTL_END;
4179
4180     // no need to switch to preemptive mode because it's very primitive operaion, doesn't take 
4181     // long and is guaranteed not to call 3rd party code. 
4182     // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4183     HRESULT hr = VarDecFromCy( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
4184     if (FAILED(hr))
4185         COMPlusThrowHR(hr);
4186
4187     if (FAILED(DecimalCanonicalize((DECIMAL*)pCLR)))
4188         COMPlusThrow(kOverflowException, W("Overflow_Currency"));
4189 }
4190
4191 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4192 {
4193     CONTRACTL
4194     {
4195         THROWS;
4196         GC_TRIGGERS;
4197         MODE_COOPERATIVE;
4198         PRECONDITION(CheckPointer(pCLR));
4199         PRECONDITION(CheckPointer(pNative));
4200     }
4201     CONTRACTL_END;
4202
4203     MethodDescCallSite convertToNative(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE);
4204     ARG_SLOT args[] =
4205     {
4206         PtrToArgSlot(pCLR),
4207         PtrToArgSlot(pNative)
4208     };
4209     convertToNative.Call(args);
4210 }
4211
4212 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4213 {
4214     CONTRACTL
4215     {
4216         THROWS;
4217         GC_TRIGGERS;
4218         MODE_COOPERATIVE;
4219         PRECONDITION(CheckPointer(pNative));
4220         PRECONDITION(CheckPointer(pCLR));
4221     }
4222     CONTRACTL_END;
4223
4224     MethodDescCallSite convertToManaged(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED);
4225     ARG_SLOT args[] =
4226     {
4227         PtrToArgSlot(pCLR),
4228         PtrToArgSlot(pNative)
4229     };
4230     convertToManaged.Call(args);
4231 }
4232
4233 #endif // FEATURE_COMINTEROP
4234
4235
4236 //=======================================================================
4237 // See FieldMarshaler for details.
4238 //=======================================================================
4239 VOID FieldMarshaler_Illegal::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4240 {
4241     CONTRACTL
4242     {
4243         THROWS;
4244         GC_TRIGGERS;
4245         MODE_COOPERATIVE;
4246         PRECONDITION(CheckPointer(pCLR));
4247         PRECONDITION(CheckPointer(pNative));
4248     }
4249     CONTRACTL_END;
4250
4251     DefineFullyQualifiedNameForClassW();
4252
4253     StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4254
4255     StackSString errorString(W("Unknown error."));
4256     errorString.LoadResource(CCompRC::Error, m_resIDWhy);
4257
4258     COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4259                  GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4260                  ssFieldName.GetUnicode(), errorString.GetUnicode());
4261 }
4262
4263
4264 //=======================================================================
4265 // See FieldMarshaler for details.
4266 //=======================================================================
4267 VOID FieldMarshaler_Illegal::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4268 {
4269     CONTRACTL
4270     {
4271         THROWS;
4272         GC_TRIGGERS;
4273         MODE_COOPERATIVE;
4274         PRECONDITION(CheckPointer(pNative));
4275         PRECONDITION(CheckPointer(pCLR));
4276     }
4277     CONTRACTL_END;
4278
4279     DefineFullyQualifiedNameForClassW();
4280
4281     StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4282
4283     StackSString errorString(W("Unknown error."));
4284     errorString.LoadResource(CCompRC::Error,m_resIDWhy);
4285
4286     COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG, 
4287                  GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4288                  ssFieldName.GetUnicode(), errorString.GetUnicode());
4289 }
4290
4291 #ifdef FEATURE_COMINTEROP
4292
4293
4294 //=======================================================================
4295 // See FieldMarshaler for details.
4296 //=======================================================================
4297 VOID FieldMarshaler_Variant::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const 
4298 {
4299     CONTRACTL
4300     {
4301         THROWS;
4302         GC_TRIGGERS;
4303         MODE_COOPERATIVE;
4304         PRECONDITION(CheckPointer(pNativeValue));
4305     }
4306     CONTRACTL_END;
4307
4308     OleVariant::MarshalOleVariantForObject(pCLRValue, (VARIANT*)pNativeValue);
4309
4310 }
4311
4312
4313 //=======================================================================
4314 // See FieldMarshaler for details.
4315 //=======================================================================
4316 VOID FieldMarshaler_Variant::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const 
4317 {
4318     CONTRACTL
4319     {
4320         THROWS;
4321         GC_TRIGGERS;
4322         MODE_COOPERATIVE;
4323         PRECONDITION(CheckPointer(pNativeValue));
4324         PRECONDITION(CheckPointer(ppProtectedCLRValue));
4325     }
4326     CONTRACTL_END;
4327
4328     OleVariant::MarshalObjectForOleVariant((VARIANT*)pNativeValue, ppProtectedCLRValue);
4329 }
4330
4331
4332 //=======================================================================
4333 // See FieldMarshaler for details.
4334 //=======================================================================
4335 VOID FieldMarshaler_Variant::DestroyNativeImpl(LPVOID pNativeValue) const 
4336 {
4337     CONTRACTL
4338     {
4339         NOTHROW;
4340         GC_TRIGGERS;
4341         MODE_ANY;
4342         PRECONDITION(CheckPointer(pNativeValue));
4343     }
4344     CONTRACTL_END;
4345
4346     SafeVariantClear( (VARIANT*)pNativeValue );
4347 }
4348
4349 #endif // FEATURE_COMINTEROP
4350
4351
4352 #ifdef _PREFAST_
4353 #pragma warning(push)
4354 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4355 #endif
4356 VOID NStructFieldTypeToString(FieldMarshaler* pFM, SString& strNStructFieldType)
4357 {
4358     CONTRACTL
4359     {
4360         THROWS;
4361         GC_NOTRIGGER;
4362         MODE_ANY;
4363         INJECT_FAULT(COMPlusThrowOM());
4364         PRECONDITION(CheckPointer(pFM));
4365     }
4366     CONTRACTL_END;
4367
4368     NStructFieldType cls = pFM->GetNStructFieldType();
4369     LPCWSTR  strRetVal;
4370     CorElementType elemType = pFM->GetFieldDesc()->GetFieldType();
4371
4372     // Some NStruct Field Types have extra information and require special handling.
4373     if (cls == NFT_FIXEDCHARARRAYANSI)
4374     {
4375         strNStructFieldType.Printf(W("fixed array of ANSI char (size = %i bytes)"), pFM->NativeSize());
4376         return;
4377     }
4378     else if (cls == NFT_FIXEDARRAY)
4379     {
4380         VARTYPE vtElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementVT();
4381         TypeHandle thElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle();
4382         BOOL fElementTypeUserDefined = FALSE;
4383
4384         // Determine if the array type is a user defined type.
4385         if (vtElement == VT_RECORD)
4386         {
4387             fElementTypeUserDefined = TRUE;
4388         }
4389         else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4390         {
4391             fElementTypeUserDefined = !thElement.IsObjectType();
4392         }
4393
4394         // Retrieve the string representation for the VARTYPE.
4395         StackSString strVarType;
4396         MarshalInfo::VarTypeToString(vtElement, strVarType);
4397
4398         MethodTable *pMT = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4399         DefineFullyQualifiedNameForClassW();
4400         WCHAR* szClassName = (WCHAR*)GetFullyQualifiedNameForClassW(pMT);
4401
4402         if (fElementTypeUserDefined)
4403         {
4404             strNStructFieldType.Printf(W("fixed array of %s exposed as %s elements (array size = %i bytes)"),
4405                                        szClassName,
4406                                        strVarType.GetUnicode(), pFM->NativeSize());
4407         }
4408         else
4409         {
4410             strNStructFieldType.Printf(W("fixed array of %s (array size = %i bytes)"), 
4411                 szClassName, pFM->NativeSize());
4412         }
4413
4414         return;
4415     }
4416 #ifdef FEATURE_COMINTEROP
4417     else if (cls == NFT_INTERFACE)
4418     {
4419         MethodTable *pItfMT     = NULL;
4420         DWORD       dwFlags     = 0;
4421
4422         ((FieldMarshaler_Interface*)pFM)->GetInterfaceInfo(&pItfMT, &dwFlags);
4423
4424         if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF)
4425         {
4426             strNStructFieldType.Set(W("IDispatch "));
4427         }
4428         else
4429         {
4430             strNStructFieldType.Set(W("IUnknown "));
4431         }
4432
4433         if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF)
4434         {
4435             strNStructFieldType.Append(W("(basic) "));
4436         }
4437             
4438
4439         if (pItfMT)
4440         {
4441             DefineFullyQualifiedNameForClassW();
4442             GetFullyQualifiedNameForClassW(pItfMT);
4443
4444             strNStructFieldType.Append(GetFullyQualifiedNameForClassW(pItfMT));
4445         }
4446
4447         return;
4448     }
4449 #ifdef FEATURE_CLASSIC_COMINTEROP
4450     else if (cls == NFT_SAFEARRAY)
4451     {
4452         VARTYPE vtElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementVT();
4453         TypeHandle thElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle();
4454         BOOL fElementTypeUserDefined = FALSE;
4455
4456         // Determine if the array type is a user defined type.
4457         if (vtElement == VT_RECORD)
4458         {
4459             fElementTypeUserDefined = TRUE;
4460         }
4461         else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4462         {
4463             fElementTypeUserDefined = !thElement.IsObjectType();
4464         }
4465
4466         // Retrieve the string representation for the VARTYPE.
4467         StackSString strVarType;
4468         MarshalInfo::VarTypeToString(vtElement, strVarType);
4469
4470
4471         StackSString strClassName;
4472         if (!thElement.IsNull())
4473         {
4474             DefineFullyQualifiedNameForClassW();
4475             MethodTable *pMT = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4476             strClassName.Set((WCHAR*)GetFullyQualifiedNameForClassW(pMT));
4477         }
4478         else
4479         {
4480             strClassName.Set(W("object"));
4481         }
4482         
4483         if (fElementTypeUserDefined)
4484         {
4485             strNStructFieldType.Printf(W("safe array of %s exposed as %s elements (array size = %i bytes)"),
4486                                        strClassName.GetUnicode(),
4487                                        strVarType.GetUnicode(), pFM->NativeSize());
4488         }
4489         else
4490         {
4491             strNStructFieldType.Printf(W("safearray of %s (array size = %i bytes)"), 
4492                 strClassName.GetUnicode(), pFM->NativeSize());
4493         }
4494         
4495         return;            
4496     }
4497 #endif // FEATURE_CLASSIC_COMINTEROP
4498 #endif // FEATURE_COMINTEROP
4499     else if (cls == NFT_NESTEDLAYOUTCLASS)
4500     {
4501         MethodTable *pMT = ((FieldMarshaler_NestedLayoutClass*)pFM)->GetMethodTable();
4502         DefineFullyQualifiedNameForClassW();
4503         strNStructFieldType.Printf(W("nested layout class %s"),
4504                                    GetFullyQualifiedNameForClassW(pMT));
4505         return;
4506     }
4507     else if (cls == NFT_NESTEDVALUECLASS)
4508     {
4509         MethodTable     *pMT                = ((FieldMarshaler_NestedValueClass*)pFM)->GetMethodTable();
4510         DefineFullyQualifiedNameForClassW();
4511         strNStructFieldType.Printf(W("nested value class %s"),
4512                                    GetFullyQualifiedNameForClassW(pMT));
4513         return;
4514     }
4515     else if (cls == NFT_COPY1)
4516     {
4517         // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy1. 
4518         switch (elemType)
4519         {
4520             case ELEMENT_TYPE_I1:
4521                 strRetVal = W("SByte");
4522                 break;
4523
4524             case ELEMENT_TYPE_U1:
4525                 strRetVal = W("Byte");
4526                 break;
4527
4528             default:
4529                 strRetVal = W("Unknown");
4530                 break;
4531         }
4532     }
4533     else if (cls == NFT_COPY2)
4534     {
4535         // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy2. 
4536         switch (elemType)
4537         {
4538             case ELEMENT_TYPE_CHAR:
4539                 strRetVal = W("Unicode char");
4540                 break;
4541
4542             case ELEMENT_TYPE_I2:
4543                 strRetVal = W("Int16");
4544                 break;
4545
4546             case ELEMENT_TYPE_U2:
4547                 strRetVal = W("UInt16");
4548                 break;
4549
4550             default:
4551                 strRetVal = W("Unknown");
4552                 break;
4553         }
4554     }
4555     else if (cls == NFT_COPY4)
4556     {
4557         // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy4. 
4558         switch (elemType)
4559         {
4560             // At this point, ELEMENT_TYPE_I must be 4 bytes long.  Same for ELEMENT_TYPE_U.
4561             case ELEMENT_TYPE_I:
4562             case ELEMENT_TYPE_I4:
4563                 strRetVal = W("Int32");
4564                 break;
4565
4566             case ELEMENT_TYPE_U:
4567             case ELEMENT_TYPE_U4:
4568                 strRetVal = W("UInt32");
4569                 break;
4570
4571             case ELEMENT_TYPE_R4:
4572                 strRetVal = W("Single");
4573                 break;
4574
4575             case ELEMENT_TYPE_PTR:
4576                 strRetVal = W("4-byte pointer");
4577                 break;
4578
4579             default:
4580                 strRetVal = W("Unknown");
4581                 break;
4582         }
4583     }
4584     else if (cls == NFT_COPY8)
4585     {
4586         // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy8. 
4587         switch (elemType)
4588         {
4589             // At this point, ELEMENT_TYPE_I must be 8 bytes long.  Same for ELEMENT_TYPE_U.
4590             case ELEMENT_TYPE_I:
4591             case ELEMENT_TYPE_I8:
4592                 strRetVal = W("Int64");
4593                 break;
4594
4595             case ELEMENT_TYPE_U:
4596             case ELEMENT_TYPE_U8:
4597                 strRetVal = W("UInt64");
4598                 break;
4599
4600             case ELEMENT_TYPE_R8:
4601                 strRetVal = W("Double");
4602                 break;
4603
4604             case ELEMENT_TYPE_PTR:
4605                 strRetVal = W("8-byte pointer");
4606                 break;
4607
4608             default:
4609                 strRetVal = W("Unknown");
4610                 break;
4611         }
4612     }
4613     else if (cls == NFT_FIXEDSTRINGUNI)
4614     {
4615         int nativeSize = pFM->NativeSize();
4616         int strLength = nativeSize / sizeof(WCHAR);
4617
4618         strNStructFieldType.Printf(W("embedded LPWSTR (length %d)"), strLength);
4619         
4620         return;
4621     }
4622     else if (cls == NFT_FIXEDSTRINGANSI)
4623     {
4624         int nativeSize = pFM->NativeSize();
4625         int strLength = nativeSize / sizeof(CHAR);
4626
4627         strNStructFieldType.Printf(W("embedded LPSTR (length %d)"), strLength);
4628
4629         return;
4630     }
4631     else
4632     {
4633         // All other NStruct Field Types which do not require special handling.
4634         switch (cls)
4635         {
4636 #ifdef FEATURE_COMINTEROP
4637             case NFT_BSTR:
4638                 strRetVal = W("BSTR");
4639                 break;
4640             case NFT_HSTRING:
4641                 strRetVal = W("HSTRING");
4642                 break;
4643 #endif  // FEATURE_COMINTEROP
4644             case NFT_STRINGUNI:
4645                 strRetVal = W("LPWSTR");
4646                 break;
4647             case NFT_STRINGANSI:
4648                 strRetVal = W("LPSTR");
4649                 break;
4650             case NFT_DELEGATE:
4651                 strRetVal = W("Delegate");
4652                 break;
4653 #ifdef FEATURE_COMINTEROP
4654             case NFT_VARIANT:
4655                 strRetVal = W("VARIANT");
4656                 break;
4657 #endif  // FEATURE_COMINTEROP
4658             case NFT_ANSICHAR:
4659                 strRetVal = W("ANSI char");
4660                 break;
4661             case NFT_WINBOOL:
4662                 strRetVal = W("Windows Bool");
4663                 break;
4664             case NFT_CBOOL:
4665                 strRetVal = W("CBool");
4666                 break;
4667             case NFT_DECIMAL:
4668                 strRetVal = W("DECIMAL");
4669                 break;
4670             case NFT_DATE:
4671                 strRetVal = W("DATE");
4672                 break;
4673 #ifdef FEATURE_COMINTEROP
4674             case NFT_VARIANTBOOL:
4675                 strRetVal = W("VARIANT Bool");
4676                 break;
4677             case NFT_CURRENCY:
4678                 strRetVal = W("CURRENCY");
4679                 break;
4680 #endif  // FEATURE_COMINTEROP
4681             case NFT_ILLEGAL:
4682                 strRetVal = W("illegal type");
4683                 break;
4684             case NFT_SAFEHANDLE:
4685                 strRetVal = W("SafeHandle");
4686                 break;
4687             case NFT_CRITICALHANDLE:
4688                 strRetVal = W("CriticalHandle");
4689                 break;
4690             default:
4691                 strRetVal = W("<UNKNOWN>");
4692                 break;
4693         }
4694     }
4695
4696     strNStructFieldType.Set(strRetVal);
4697
4698     return;
4699 }
4700 #ifdef _PREFAST_
4701 #pragma warning(pop)
4702 #endif
4703
4704 #endif // CROSSGEN_COMPILE
4705
4706
4707 //
4708 // Implementation of the virtual functions using switch statements.
4709 //
4710 // We are not able bake pointers to the FieldMarshaller vtables into NGen images. We store
4711 // the field marshaller id instead, and implement the virtualization by switch based on the id.
4712 //
4713
4714 #ifdef FEATURE_CLASSIC_COMINTEROP
4715 #define FieldMarshaler_SafeArray_Case(rettype, name, args) case NFT_SAFEARRAY: rettype ((FieldMarshaler_SafeArray*)this)->name##Impl args; break;
4716 #else
4717 #define FieldMarshaler_SafeArray_Case(rettype, name, args)
4718 #endif
4719
4720 #ifdef FEATURE_COMINTEROP
4721
4722 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4723     ret FieldMarshaler::name argsdecl { \
4724         WRAPPER_NO_CONTRACT; \
4725         switch (GetNStructFieldType()) { \
4726         case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4727         case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4728         case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4729         case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4730         case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4731         case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4732         case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4733         case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4734         case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4735         case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4736         case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4737         case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4738         case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4739         case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4740         case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4741         case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4742         case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4743         case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4744         case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4745         case NFT_INTERFACE: rettype ((FieldMarshaler_Interface*)this)->name##Impl args; break; \
4746         case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4747         case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4748         FieldMarshaler_SafeArray_Case(rettype, name, args) \
4749         case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \
4750         case NFT_HSTRING: rettype ((FieldMarshaler_HSTRING*)this)->name##Impl args; break; \
4751         case NFT_VARIANT: rettype ((FieldMarshaler_Variant*)this)->name##Impl args; break; \
4752         case NFT_VARIANTBOOL: rettype ((FieldMarshaler_VariantBool*)this)->name##Impl args; break; \
4753         case NFT_CURRENCY: rettype ((FieldMarshaler_Currency*)this)->name##Impl args; break; \
4754         case NFT_DATETIMEOFFSET: rettype ((FieldMarshaler_DateTimeOffset*)this)->name##Impl args; break; \
4755         case NFT_SYSTEMTYPE: rettype ((FieldMarshaler_SystemType *)this)->name##Impl args; break; \
4756         case NFT_WINDOWSFOUNDATIONHRESULT: rettype ((FieldMarshaler_Exception*)this)->name##Impl args; break; \
4757         case NFT_WINDOWSFOUNDATIONIREFERENCE: rettype ((FieldMarshaler_Nullable*)this)->name##Impl args; break; \
4758         case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4759         default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4760         } \
4761     }
4762
4763 #else // FEATURE_COMINTEROP
4764
4765 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4766     ret FieldMarshaler::name argsdecl { \
4767         WRAPPER_NO_CONTRACT; \
4768         switch (GetNStructFieldType()) { \
4769         case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4770         case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4771         case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4772         case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4773         case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4774         case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4775         case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4776         case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4777         case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4778         case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4779         case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4780         case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4781         case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4782         case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4783         case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4784         case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4785         case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4786         case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4787         case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4788         case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4789         case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4790         case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4791         default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4792         } \
4793     }
4794
4795 #endif // FEATURE_COMINTEROP
4796
4797
4798 IMPLEMENT_FieldMarshaler_METHOD(UINT32, NativeSize,
4799     () const,
4800     return,
4801     ())
4802
4803 IMPLEMENT_FieldMarshaler_METHOD(UINT32, AlignmentRequirement,
4804     () const,
4805     return,
4806     ())
4807
4808 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsScalarMarshaler,
4809     () const,
4810     return,
4811     ())
4812
4813 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsNestedValueClassMarshaler,
4814     () const,
4815     return,
4816     ())
4817
4818 #ifndef CROSSGEN_COMPILE
4819 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateNative,
4820     (OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const,
4821     ,
4822     (pCLRValue, pNativeValue, ppCleanupWorkListOnStack))
4823
4824 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateCLR,
4825     (const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const,
4826     ,
4827     (pNativeValue, ppProtectedCLRValue, ppProtectedOldCLRValue))
4828
4829 IMPLEMENT_FieldMarshaler_METHOD(VOID, DestroyNative,
4830     (LPVOID pNativeValue) const,
4831     ,
4832     (pNativeValue))
4833
4834 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateNative,
4835     (LPVOID pCLR, LPVOID pNative) const,
4836     return,
4837     (pCLR, pNative))
4838
4839 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateCLR,
4840     (const VOID *pNative, LPVOID pCLR) const,
4841     return,
4842     (pNative, pCLR))
4843
4844 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateNative,
4845     (const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const,
4846     ,
4847     (ppProtectedCLR, startoffset, pNative, ppCleanupWorkListOnStack))
4848
4849 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateCLR,
4850     (const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const,
4851     ,
4852     (pNative, ppProtectedCLR, startoffset))
4853 #endif // CROSSGEN_COMPILE
4854
4855 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4856 IMPLEMENT_FieldMarshaler_METHOD(void, Save,
4857     (DataImage *image),
4858     ,
4859     (image))
4860
4861 IMPLEMENT_FieldMarshaler_METHOD(void, Fixup,
4862     (DataImage *image),
4863     ,
4864     (image))
4865 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4866
4867 IMPLEMENT_FieldMarshaler_METHOD(void, Restore,
4868     (),
4869     ,
4870     ())
4871
4872 #ifndef DACCESS_COMPILE
4873 IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo,
4874     (VOID *pDest, SIZE_T destSize) const,
4875     ,
4876     (pDest, destSize))
4877 #endif // !DACCESS_COMPILE