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