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