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: CustomMarshalerInfo.cpp
6//
7
8//
9// Custom marshaler information used when marshaling
10// a parameter with a custom marshaler.
11//
12
13
14#include "common.h"
15
16
17#include "custommarshalerinfo.h"
18#include "mlinfo.h"
19#include "mdaassistants.h"
20#include "sigbuilder.h"
21
22//==========================================================================
23// Implementation of the custom marshaler info class.
24//==========================================================================
25
26CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes)
27: m_NativeSize(0)
28, m_hndManagedType(hndManagedType)
29, m_hndCustomMarshaler(NULL)
30, m_pMarshalNativeToManagedMD(NULL)
31, m_pMarshalManagedToNativeMD(NULL)
32, m_pCleanUpNativeDataMD(NULL)
33, m_pCleanUpManagedDataMD(NULL)
34, m_bDataIsByValue(FALSE)
35{
36 CONTRACTL
37 {
38 THROWS;
39 GC_TRIGGERS;
40 MODE_COOPERATIVE;
41 PRECONDITION(CheckPointer(pDomain));
42 }
43 CONTRACTL_END;
44
45
46 // Make sure the custom marshaller implements ICustomMarshaler.
47 if (!hndCustomMarshalerType.GetMethodTable()->CanCastToNonVariantInterface(MscorlibBinder::GetClass(CLASS__ICUSTOM_MARSHALER)))
48 {
49 DefineFullyQualifiedNameForClassW()
50 COMPlusThrow(kApplicationException,
51 IDS_EE_ICUSTOMMARSHALERNOTIMPL,
52 GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable()));
53 }
54
55 // Determine if this type is a value class.
56 m_bDataIsByValue = m_hndManagedType.GetMethodTable()->IsValueType();
57
58 // Custom marshalling of value classes is not currently supported.
59 if (m_bDataIsByValue)
60 COMPlusThrow(kNotSupportedException, W("NotSupported_ValueClassCM"));
61
62#ifndef CROSSGEN_COMPILE
63 // Run the <clinit> on the marshaler since it might not have run yet.
64 hndCustomMarshalerType.GetMethodTable()->EnsureInstanceActive();
65 hndCustomMarshalerType.GetMethodTable()->CheckRunClassInitThrowing();
66
67 // Create a COM+ string that will contain the string cookie.
68 STRINGREF CookieStringObj = StringObject::NewString(strCookie, cCookieStrBytes);
69 GCPROTECT_BEGIN(CookieStringObj);
70#endif
71
72 // Load the method desc's for all the methods in the ICustomMarshaler interface.
73 m_pMarshalNativeToManagedMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalNativeToManaged, hndCustomMarshalerType);
74 m_pMarshalManagedToNativeMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalManagedToNative, hndCustomMarshalerType);
75 m_pCleanUpNativeDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpNativeData, hndCustomMarshalerType);
76 m_pCleanUpManagedDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpManagedData, hndCustomMarshalerType);
77
78 // Load the method desc for the static method to retrieve the instance.
79 MethodDesc *pGetCustomMarshalerMD = GetCustomMarshalerMD(CustomMarshalerMethods_GetInstance, hndCustomMarshalerType);
80
81 // If the GetInstance method is generic, get an instantiating stub for it -
82 // the CallDescr infrastructure doesn't know how to pass secret generic arguments.
83 if (pGetCustomMarshalerMD->RequiresInstMethodTableArg())
84 {
85 pGetCustomMarshalerMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
86 pGetCustomMarshalerMD,
87 hndCustomMarshalerType.GetMethodTable(),
88 FALSE, // forceBoxedEntryPoint
89 Instantiation(), // methodInst
90 FALSE, // allowInstParam
91 FALSE); // forceRemotableMethod
92
93 _ASSERTE(!pGetCustomMarshalerMD->RequiresInstMethodTableArg());
94 }
95
96#ifndef CROSSGEN_COMPILE
97 MethodDescCallSite getCustomMarshaler(pGetCustomMarshalerMD, (OBJECTREF*)&CookieStringObj);
98
99 pGetCustomMarshalerMD->EnsureActive();
100
101 // Prepare the arguments that will be passed to GetCustomMarshaler.
102 ARG_SLOT GetCustomMarshalerArgs[] = {
103 ObjToArgSlot(CookieStringObj)
104 };
105
106 // Call the GetCustomMarshaler method to retrieve the custom marshaler to use.
107 OBJECTREF CustomMarshalerObj = getCustomMarshaler.Call_RetOBJECTREF(GetCustomMarshalerArgs);
108 if (!CustomMarshalerObj)
109 {
110 DefineFullyQualifiedNameForClassW()
111 COMPlusThrow(kApplicationException,
112 IDS_EE_NOCUSTOMMARSHALER,
113 GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable()));
114 }
115 m_hndCustomMarshaler = pDomain->CreateHandle(CustomMarshalerObj);
116
117 // Retrieve the size of the native data.
118 if (m_bDataIsByValue)
119 {
120 // <TODO>@TODO(DM): Call GetNativeDataSize() to retrieve the size of the native data.</TODO>
121 _ASSERTE(!"Value classes are not yet supported by the custom marshaler!");
122 }
123 else
124 {
125 m_NativeSize = sizeof(void *);
126 }
127
128 GCPROTECT_END();
129#endif
130}
131
132
133CustomMarshalerInfo::~CustomMarshalerInfo()
134{
135 WRAPPER_NO_CONTRACT;
136#ifndef CROSSGEN_COMPILE
137 if (m_hndCustomMarshaler)
138 {
139 DestroyHandle(m_hndCustomMarshaler);
140 m_hndCustomMarshaler = NULL;
141 }
142#endif
143}
144
145
146void *CustomMarshalerInfo::operator new(size_t size, LoaderHeap *pHeap)
147{
148 CONTRACTL
149 {
150 THROWS;
151 GC_NOTRIGGER;
152 MODE_ANY;
153 INJECT_FAULT(COMPlusThrowOM());
154 PRECONDITION(CheckPointer(pHeap));
155 }
156 CONTRACTL_END;
157
158 return pHeap->AllocMem(S_SIZE_T(sizeof(CustomMarshalerInfo)));
159}
160
161
162void CustomMarshalerInfo::operator delete(void *pMem)
163{
164 // Instances of this class are always allocated on the loader heap so
165 // the delete operator has nothing to do.
166 LIMITED_METHOD_CONTRACT;
167}
168
169#ifndef CROSSGEN_COMPILE
170OBJECTREF CustomMarshalerInfo::InvokeMarshalNativeToManagedMeth(void *pNative)
171{
172 CONTRACTL
173 {
174 THROWS;
175 GC_TRIGGERS;
176 MODE_COOPERATIVE;
177 PRECONDITION(CheckPointer(pNative, NULL_OK));
178 }
179 CONTRACTL_END;
180
181 if (!pNative)
182 return NULL;
183
184 MethodDescCallSite marshalNativeToManaged(m_pMarshalNativeToManagedMD, m_hndCustomMarshaler);
185
186 ARG_SLOT Args[] = {
187 ObjToArgSlot(ObjectFromHandle(m_hndCustomMarshaler)),
188 PtrToArgSlot(pNative)
189 };
190
191 return marshalNativeToManaged.Call_RetOBJECTREF(Args);
192}
193
194
195void *CustomMarshalerInfo::InvokeMarshalManagedToNativeMeth(OBJECTREF MngObj)
196{
197 CONTRACTL
198 {
199 THROWS;
200 GC_TRIGGERS;
201 MODE_COOPERATIVE;
202 }
203 CONTRACTL_END;
204
205 void *RetVal = NULL;
206
207 if (!MngObj)
208 return NULL;
209
210 GCPROTECT_BEGIN (MngObj);
211 MethodDescCallSite marshalManagedToNative(m_pMarshalManagedToNativeMD, m_hndCustomMarshaler);
212
213 ARG_SLOT Args[] = {
214 ObjToArgSlot(ObjectFromHandle(m_hndCustomMarshaler)),
215 ObjToArgSlot(MngObj)
216 };
217
218 RetVal = marshalManagedToNative.Call_RetLPVOID(Args);
219 GCPROTECT_END ();
220
221 return RetVal;
222}
223
224
225void CustomMarshalerInfo::InvokeCleanUpNativeMeth(void *pNative)
226{
227 CONTRACTL
228 {
229 THROWS;
230 GC_TRIGGERS;
231 MODE_COOPERATIVE;
232 PRECONDITION(CheckPointer(pNative, NULL_OK));
233 }
234 CONTRACTL_END;
235
236 if (!pNative)
237 return;
238
239 MethodDescCallSite cleanUpNativeData(m_pCleanUpNativeDataMD, m_hndCustomMarshaler);
240
241 ARG_SLOT Args[] = {
242 ObjToArgSlot(ObjectFromHandle(m_hndCustomMarshaler)),
243 PtrToArgSlot(pNative)
244 };
245
246 cleanUpNativeData.Call(Args);
247}
248
249
250void CustomMarshalerInfo::InvokeCleanUpManagedMeth(OBJECTREF MngObj)
251{
252 CONTRACTL
253 {
254 THROWS;
255 GC_TRIGGERS;
256 MODE_COOPERATIVE;
257 }
258 CONTRACTL_END;
259
260 if (!MngObj)
261 return;
262
263 GCPROTECT_BEGIN (MngObj);
264 MethodDescCallSite cleanUpManagedData(m_pCleanUpManagedDataMD, m_hndCustomMarshaler);
265
266 ARG_SLOT Args[] = {
267 ObjToArgSlot(ObjectFromHandle(m_hndCustomMarshaler)),
268 ObjToArgSlot(MngObj)
269 };
270
271 cleanUpManagedData.Call(Args);
272 GCPROTECT_END ();
273}
274
275#endif // CROSSGEN_COMPILE
276MethodDesc *CustomMarshalerInfo::GetCustomMarshalerMD(EnumCustomMarshalerMethods Method, TypeHandle hndCustomMarshalertype)
277{
278 CONTRACTL
279 {
280 THROWS;
281 GC_TRIGGERS;
282 MODE_COOPERATIVE;
283 }
284 CONTRACTL_END;
285
286
287 MethodTable *pMT = hndCustomMarshalertype.AsMethodTable();
288
289 _ASSERTE(pMT->CanCastToNonVariantInterface(MscorlibBinder::GetClass(CLASS__ICUSTOM_MARSHALER)));
290
291 MethodDesc *pMD = NULL;
292
293 switch (Method)
294 {
295 case CustomMarshalerMethods_MarshalNativeToManaged:
296 pMD = pMT->GetMethodDescForInterfaceMethod(
297 MscorlibBinder::GetMethod(METHOD__ICUSTOM_MARSHALER__MARSHAL_NATIVE_TO_MANAGED),
298 TRUE /* throwOnConflict */);
299 break;
300 case CustomMarshalerMethods_MarshalManagedToNative:
301 pMD = pMT->GetMethodDescForInterfaceMethod(
302 MscorlibBinder::GetMethod(METHOD__ICUSTOM_MARSHALER__MARSHAL_MANAGED_TO_NATIVE),
303 TRUE /* throwOnConflict */);
304 break;
305 case CustomMarshalerMethods_CleanUpNativeData:
306 pMD = pMT->GetMethodDescForInterfaceMethod(
307 MscorlibBinder::GetMethod(METHOD__ICUSTOM_MARSHALER__CLEANUP_NATIVE_DATA),
308 TRUE /* throwOnConflict */);
309 break;
310
311 case CustomMarshalerMethods_CleanUpManagedData:
312 pMD = pMT->GetMethodDescForInterfaceMethod(
313 MscorlibBinder::GetMethod(METHOD__ICUSTOM_MARSHALER__CLEANUP_MANAGED_DATA),
314 TRUE /* throwOnConflict */);
315 break;
316 case CustomMarshalerMethods_GetNativeDataSize:
317 pMD = pMT->GetMethodDescForInterfaceMethod(
318 MscorlibBinder::GetMethod(METHOD__ICUSTOM_MARSHALER__GET_NATIVE_DATA_SIZE),
319 TRUE /* throwOnConflict */);
320 break;
321 case CustomMarshalerMethods_GetInstance:
322 // Must look this up by name since it's static
323 pMD = MemberLoader::FindMethod(pMT, "GetInstance", &gsig_SM_Str_RetICustomMarshaler);
324 if (!pMD)
325 {
326 DefineFullyQualifiedNameForClassW()
327 COMPlusThrow(kApplicationException,
328 IDS_EE_GETINSTANCENOTIMPL,
329 GetFullyQualifiedNameForClassW(pMT));
330 }
331 break;
332 default:
333 _ASSERTE(!"Unknown custom marshaler method");
334 }
335
336 _ASSERTE(pMD && "Unable to find specified CustomMarshaler method");
337
338 // Ensure that the value types in the signature are loaded.
339 MetaSig::EnsureSigValueTypesLoaded(pMD);
340
341 // Return the specified method desc.
342 return pMD;
343}
344
345#ifndef CROSSGEN_COMPILE
346
347//==========================================================================
348// Implementation of the custom marshaler hashtable helper.
349//==========================================================================
350
351EEHashEntry_t * EECMHelperHashtableHelper::AllocateEntry(EECMHelperHashtableKey *pKey, BOOL bDeepCopy, void* pHeap)
352{
353 CONTRACTL
354 {
355 NOTHROW;
356 GC_NOTRIGGER;
357 MODE_ANY;
358 INJECT_FAULT(return NULL;);
359 }
360 CONTRACTL_END;
361
362 EEHashEntry_t *pEntry;
363
364 if (bDeepCopy)
365 {
366 S_SIZE_T cbEntry = S_SIZE_T(sizeof(EEHashEntry) - 1 + sizeof(EECMHelperHashtableKey));
367 cbEntry += S_SIZE_T(pKey->GetMarshalerTypeNameByteCount());
368 cbEntry += S_SIZE_T(pKey->GetCookieStringByteCount());
369 cbEntry += S_SIZE_T(pKey->GetMarshalerInstantiation().GetNumArgs()) * S_SIZE_T(sizeof(LPVOID));
370
371 if (cbEntry.IsOverflow())
372 return NULL;
373
374 pEntry = (EEHashEntry_t *) new (nothrow) BYTE[cbEntry.Value()];
375 if (!pEntry)
376 return NULL;
377
378 EECMHelperHashtableKey *pEntryKey = (EECMHelperHashtableKey *) pEntry->Key;
379 pEntryKey->m_cMarshalerTypeNameBytes = pKey->GetMarshalerTypeNameByteCount();
380 pEntryKey->m_strMarshalerTypeName = (LPSTR) pEntry->Key + sizeof(EECMHelperHashtableKey);
381 pEntryKey->m_cCookieStrBytes = pKey->GetCookieStringByteCount();
382 pEntryKey->m_strCookie = (LPSTR) pEntry->Key + sizeof(EECMHelperHashtableKey) + pEntryKey->m_cMarshalerTypeNameBytes;
383 pEntryKey->m_Instantiation = Instantiation(
384 (TypeHandle *) (pEntryKey->m_strCookie + pEntryKey->m_cCookieStrBytes),
385 pKey->GetMarshalerInstantiation().GetNumArgs());
386 memcpy((void*)pEntryKey->m_strMarshalerTypeName, pKey->GetMarshalerTypeName(), pKey->GetMarshalerTypeNameByteCount());
387 memcpy((void*)pEntryKey->m_strCookie, pKey->GetCookieString(), pKey->GetCookieStringByteCount());
388 memcpy((void*)pEntryKey->m_Instantiation.GetRawArgs(), pKey->GetMarshalerInstantiation().GetRawArgs(),
389 pEntryKey->m_Instantiation.GetNumArgs() * sizeof(LPVOID));
390 }
391 else
392 {
393 pEntry = (EEHashEntry_t *)
394 new (nothrow) BYTE[sizeof(EEHashEntry) - 1 + sizeof(EECMHelperHashtableKey)];
395 if (!pEntry)
396 return NULL;
397
398 EECMHelperHashtableKey *pEntryKey = (EECMHelperHashtableKey *) pEntry->Key;
399 pEntryKey->m_cMarshalerTypeNameBytes = pKey->GetMarshalerTypeNameByteCount();
400 pEntryKey->m_strMarshalerTypeName = pKey->GetMarshalerTypeName();
401 pEntryKey->m_cCookieStrBytes = pKey->GetCookieStringByteCount();
402 pEntryKey->m_strCookie = pKey->GetCookieString();
403 pEntryKey->m_Instantiation = Instantiation(pKey->GetMarshalerInstantiation());
404 }
405
406 return pEntry;
407}
408
409
410void EECMHelperHashtableHelper::DeleteEntry(EEHashEntry_t *pEntry, void* pHeap)
411{
412 CONTRACTL
413 {
414 NOTHROW;
415 GC_NOTRIGGER;
416 MODE_ANY;
417 PRECONDITION(CheckPointer(pEntry));
418 }
419 CONTRACTL_END;
420
421 delete[] (BYTE*)pEntry;
422}
423
424
425BOOL EECMHelperHashtableHelper::CompareKeys(EEHashEntry_t *pEntry, EECMHelperHashtableKey *pKey)
426{
427 CONTRACTL
428 {
429 NOTHROW;
430 GC_NOTRIGGER;
431 MODE_ANY;
432 PRECONDITION(CheckPointer(pEntry));
433 PRECONDITION(CheckPointer(pKey));
434 }
435 CONTRACTL_END;
436
437 EECMHelperHashtableKey *pEntryKey = (EECMHelperHashtableKey *) pEntry->Key;
438
439 if (pEntryKey->GetMarshalerTypeNameByteCount() != pKey->GetMarshalerTypeNameByteCount())
440 return FALSE;
441
442 if (memcmp(pEntryKey->GetMarshalerTypeName(), pKey->GetMarshalerTypeName(), pEntryKey->GetMarshalerTypeNameByteCount()) != 0)
443 return FALSE;
444
445 if (pEntryKey->GetCookieStringByteCount() != pKey->GetCookieStringByteCount())
446 return FALSE;
447
448 if (memcmp(pEntryKey->GetCookieString(), pKey->GetCookieString(), pEntryKey->GetCookieStringByteCount()) != 0)
449 return FALSE;
450
451 DWORD dwNumTypeArgs = pEntryKey->GetMarshalerInstantiation().GetNumArgs();
452 if (dwNumTypeArgs != pKey->GetMarshalerInstantiation().GetNumArgs())
453 return FALSE;
454
455 for (DWORD i = 0; i < dwNumTypeArgs; i++)
456 {
457 if (pEntryKey->GetMarshalerInstantiation()[i] != pKey->GetMarshalerInstantiation()[i])
458 return FALSE;
459 }
460
461 return TRUE;
462}
463
464
465DWORD EECMHelperHashtableHelper::Hash(EECMHelperHashtableKey *pKey)
466{
467 WRAPPER_NO_CONTRACT;
468
469 return (DWORD)
470 (HashBytes((const BYTE *) pKey->GetMarshalerTypeName(), pKey->GetMarshalerTypeNameByteCount()) +
471 HashBytes((const BYTE *) pKey->GetCookieString(), pKey->GetCookieStringByteCount()) +
472 HashBytes((const BYTE *) pKey->GetMarshalerInstantiation().GetRawArgs(), pKey->GetMarshalerInstantiation().GetNumArgs() * sizeof(LPVOID)));
473}
474
475
476OBJECTREF CustomMarshalerHelper::InvokeMarshalNativeToManagedMeth(void *pNative)
477{
478 WRAPPER_NO_CONTRACT;
479 return GetCustomMarshalerInfo()->InvokeMarshalNativeToManagedMeth(pNative);
480}
481
482
483void *CustomMarshalerHelper::InvokeMarshalManagedToNativeMeth(OBJECTREF MngObj)
484{
485 CONTRACTL
486 {
487 THROWS;
488 GC_TRIGGERS;
489 MODE_COOPERATIVE;
490 }
491 CONTRACTL_END;
492
493 void *RetVal = NULL;
494
495 GCPROTECT_BEGIN(MngObj)
496 {
497 CustomMarshalerInfo *pCMInfo = GetCustomMarshalerInfo();
498 RetVal = pCMInfo->InvokeMarshalManagedToNativeMeth(MngObj);
499 }
500 GCPROTECT_END();
501
502 return RetVal;
503}
504
505
506void CustomMarshalerHelper::InvokeCleanUpNativeMeth(void *pNative)
507{
508 CONTRACTL
509 {
510 THROWS;
511 GC_TRIGGERS;
512 MODE_COOPERATIVE;
513 }
514 CONTRACTL_END;
515
516 OBJECTREF ExceptionObj = NULL;
517 GCPROTECT_BEGIN(ExceptionObj)
518 {
519 EX_TRY
520 {
521 GetCustomMarshalerInfo()->InvokeCleanUpNativeMeth(pNative);
522 }
523 EX_CATCH
524 {
525 ExceptionObj = GET_THROWABLE();
526 }
527 EX_END_CATCH(SwallowAllExceptions);
528
529#ifdef MDA_SUPPORTED
530 if (ExceptionObj != NULL)
531 {
532 TypeHandle typeCustomMarshaler = GetCustomMarshalerInfo()->GetCustomMarshalerType();
533 MDA_TRIGGER_ASSISTANT(MarshalCleanupError, ReportErrorCustomMarshalerCleanup(typeCustomMarshaler, &ExceptionObj));
534 }
535#endif
536 }
537 GCPROTECT_END();
538}
539
540
541void CustomMarshalerHelper::InvokeCleanUpManagedMeth(OBJECTREF MngObj)
542{
543 CONTRACTL
544 {
545 THROWS;
546 GC_TRIGGERS;
547 MODE_COOPERATIVE;
548 }
549 CONTRACTL_END;
550
551 GCPROTECT_BEGIN(MngObj)
552 {
553 CustomMarshalerInfo *pCMInfo = GetCustomMarshalerInfo();
554 pCMInfo->InvokeCleanUpManagedMeth(MngObj);
555 }
556 GCPROTECT_END();
557}
558
559
560void *NonSharedCustomMarshalerHelper::operator new(size_t size, LoaderHeap *pHeap)
561{
562 CONTRACTL
563 {
564 THROWS;
565 GC_NOTRIGGER;
566 MODE_ANY;
567 INJECT_FAULT(COMPlusThrowOM());
568 PRECONDITION(CheckPointer(pHeap));
569 }
570 CONTRACTL_END;
571
572 return pHeap->AllocMem(S_SIZE_T(sizeof(NonSharedCustomMarshalerHelper)));
573}
574
575
576void NonSharedCustomMarshalerHelper::operator delete(void *pMem)
577{
578 // Instances of this class are always allocated on the loader heap so
579 // the delete operator has nothing to do.
580 LIMITED_METHOD_CONTRACT;
581}
582
583
584SharedCustomMarshalerHelper::SharedCustomMarshalerHelper(Assembly *pAssembly, TypeHandle hndManagedType, LPCUTF8 strMarshalerTypeName, DWORD cMarshalerTypeNameBytes, LPCUTF8 strCookie, DWORD cCookieStrBytes)
585: m_pAssembly(pAssembly)
586, m_hndManagedType(hndManagedType)
587, m_cMarshalerTypeNameBytes(cMarshalerTypeNameBytes)
588, m_strMarshalerTypeName(strMarshalerTypeName)
589, m_cCookieStrBytes(cCookieStrBytes)
590, m_strCookie(strCookie)
591{
592 WRAPPER_NO_CONTRACT;
593}
594
595
596void *SharedCustomMarshalerHelper::operator new(size_t size, LoaderHeap *pHeap)
597{
598 CONTRACTL
599 {
600 THROWS;
601 GC_NOTRIGGER;
602 MODE_ANY;
603 INJECT_FAULT(COMPlusThrowOM());
604 PRECONDITION(CheckPointer(pHeap));
605 }
606 CONTRACTL_END;
607
608 return pHeap->AllocMem(S_SIZE_T(sizeof(SharedCustomMarshalerHelper)));
609}
610
611
612void SharedCustomMarshalerHelper::operator delete(void *pMem)
613{
614 // Instances of this class are always allocated on the loader heap so
615 // the delete operator has nothing to do.
616 LIMITED_METHOD_CONTRACT;
617}
618
619
620CustomMarshalerInfo *SharedCustomMarshalerHelper::GetCustomMarshalerInfo()
621{
622 CONTRACTL
623 {
624 THROWS;
625 GC_TRIGGERS;
626 MODE_COOPERATIVE;
627 }
628 CONTRACTL_END;
629
630 // Retrieve the marshalling data for the current app domain.
631 EEMarshalingData *pMarshalingData = GetThread()->GetDomain()->GetMarshalingData();
632
633 // Retrieve the custom marshaling information for the current shared custom
634 // marshaling helper.
635 return pMarshalingData->GetCustomMarshalerInfo(this);
636}
637
638
639#endif // CROSSGEN_COMPILE
640
641