Add tests for ANSI BSTRs (#20985)
[platform/upstream/coreclr.git] / src / vm / ilmarshalers.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // 
5 // File: ILMarshalers.cpp
6 // 
7
8 // 
9
10
11 #include "common.h"
12 #include "dllimport.h"
13 #include "mlinfo.h"
14 #include "ilmarshalers.h"
15 #include "olevariant.h"
16 #include "comdatetime.h"
17 #include "fieldmarshaler.h"
18
19 LocalDesc ILReflectionObjectMarshaler::GetManagedType()
20 {
21     STANDARD_VM_CONTRACT;
22     
23     return LocalDesc(MscorlibBinder::GetClass(GetManagedTypeBinderID()));
24 }
25
26 LocalDesc ILReflectionObjectMarshaler::GetNativeType()
27 {
28     LIMITED_METHOD_CONTRACT;
29     
30     return LocalDesc(ELEMENT_TYPE_I);
31 }
32
33 void ILReflectionObjectMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
34 {
35     STANDARD_VM_CONTRACT;
36     
37     int tokObject__m_handle = pslILEmit->GetToken(MscorlibBinder::GetField(GetObjectFieldID()));
38     int tokStruct__m_object = 0;
39     BinderFieldID structField = GetStructureFieldID();
40
41     // This marshaler can generate code for marshaling an object containing a handle, and for 
42     // marshaling a struct referring to an object containing a handle.
43     if (structField != 0)
44     {
45         tokStruct__m_object = pslILEmit->GetToken(MscorlibBinder::GetField(structField));
46     }
47     
48     ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
49
50     pslILEmit->EmitLoadNullPtr();
51     EmitStoreNativeValue(pslILEmit);
52
53     if (tokStruct__m_object != 0)
54     {
55         EmitLoadManagedHomeAddr(pslILEmit);
56         pslILEmit->EmitLDFLD(tokStruct__m_object);
57     }
58     else
59     {
60         EmitLoadManagedValue(pslILEmit);
61     }
62     pslILEmit->EmitBRFALSE(pNullLabel);
63     
64     if (tokStruct__m_object != 0)
65     {
66         EmitLoadManagedHomeAddr(pslILEmit);
67         pslILEmit->EmitLDFLD(tokStruct__m_object);
68     }
69     else
70     {
71         EmitLoadManagedValue(pslILEmit);
72     }
73
74     pslILEmit->EmitLDFLD(tokObject__m_handle);
75     EmitStoreNativeValue(pslILEmit);
76     
77     pslILEmit->EmitLabel(pNullLabel);
78
79     if (IsCLRToNative(m_dwMarshalFlags))
80     {
81         // keep the object alive across the call-out to native
82         if (tokStruct__m_object != 0)
83         {
84             EmitLoadManagedHomeAddr(m_pcsUnmarshal);
85             m_pcsUnmarshal->EmitLDFLD(tokStruct__m_object);
86         }
87         else
88         {
89             EmitLoadManagedValue(m_pcsUnmarshal);
90         }
91         m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
92     }
93 }
94
95 void ILReflectionObjectMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
96 {
97     STANDARD_VM_CONTRACT;
98     
99     COMPlusThrow(kTypeLoadException, IDS_EE_COM_UNSUPPORTED_SIG);
100 }
101
102 LocalDesc ILDelegateMarshaler::GetNativeType()
103 {
104     LIMITED_METHOD_CONTRACT;
105     
106     return LocalDesc(ELEMENT_TYPE_I);
107 }
108
109 LocalDesc ILDelegateMarshaler::GetManagedType()
110 {
111     LIMITED_METHOD_CONTRACT;
112     
113     return LocalDesc(m_pargs->m_pMT);
114 }
115
116 void ILDelegateMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
117 {
118     STANDARD_VM_CONTRACT;
119            
120     ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
121
122     pslILEmit->EmitLoadNullPtr();
123     EmitStoreNativeValue(pslILEmit);
124
125     EmitLoadManagedValue(pslILEmit);
126     pslILEmit->EmitBRFALSE(pNullLabel);
127     
128     EmitLoadManagedValue(pslILEmit);
129     pslILEmit->EmitCALL(METHOD__MARSHAL__GET_FUNCTION_POINTER_FOR_DELEGATE, 1, 1);
130     EmitStoreNativeValue(pslILEmit);
131     
132     pslILEmit->EmitLabel(pNullLabel);
133
134     //
135     // @TODO: is there a better way to do this?
136     //
137     if (IsCLRToNative(m_dwMarshalFlags))
138     {
139         // keep the delegate ref alive across the call-out to native
140         EmitLoadManagedValue(m_pcsUnmarshal);
141         m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
142     }
143 }
144
145 void ILDelegateMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
146 {
147     STANDARD_VM_CONTRACT;
148     
149     ILCodeLabel* pNullLabel = pslILEmit->NewCodeLabel();
150
151     EmitLoadNativeValue(pslILEmit);
152     pslILEmit->EmitBRFALSE(pNullLabel);
153
154     EmitLoadNativeValue(pslILEmit);
155     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
156     pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1); // Type System.Type.GetTypeFromHandle(RuntimeTypeHandle handle)
157     pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER, 2, 1); // Delegate System.Marshal.GetDelegateForFunctionPointer(IntPtr p, Type t)
158     EmitStoreManagedValue(pslILEmit);
159
160     pslILEmit->EmitLabel(pNullLabel);
161 }
162
163
164 LocalDesc ILBoolMarshaler::GetNativeType()
165 {
166     LIMITED_METHOD_CONTRACT;
167     
168     return LocalDesc(GetNativeBoolElementType());
169 }
170
171 LocalDesc ILBoolMarshaler::GetManagedType()
172 {
173     LIMITED_METHOD_CONTRACT;
174     
175     return LocalDesc(ELEMENT_TYPE_BOOLEAN);
176 }
177
178 void ILBoolMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
179 {
180     STANDARD_VM_CONTRACT;
181
182     ILCodeLabel* pLoadFalseLabel = pslILEmit->NewCodeLabel();
183     ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
184
185
186     int trueValue = GetNativeTrueValue();
187     int falseValue = GetNativeFalseValue();
188
189     EmitLoadManagedValue(pslILEmit);
190
191     if (falseValue == 0 && trueValue == 1)
192     {
193         // this can be done without jumps
194         pslILEmit->EmitLDC(0);
195         pslILEmit->EmitCEQ();
196         pslILEmit->EmitLDC(0);
197         pslILEmit->EmitCEQ();
198     }
199     else
200     {
201         pslILEmit->EmitBRFALSE(pLoadFalseLabel);
202         pslILEmit->EmitLDC(trueValue);
203         pslILEmit->EmitBR(pDoneLabel);
204 #ifdef _DEBUG
205         pslILEmit->EmitPOP();   // keep the simple stack level calculator happy 
206 #endif // _DEBUG
207         pslILEmit->EmitLabel(pLoadFalseLabel);
208         pslILEmit->EmitLDC(falseValue);
209         pslILEmit->EmitLabel(pDoneLabel);
210     }
211
212     EmitStoreNativeValue(pslILEmit);
213 }
214
215 void ILBoolMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
216 {
217     STANDARD_VM_CONTRACT;
218     
219     int falseValue = GetNativeFalseValue();
220
221     EmitLoadNativeValue(pslILEmit);
222
223     pslILEmit->EmitLDC(falseValue);
224     pslILEmit->EmitCEQ();
225     pslILEmit->EmitLDC(0);
226     pslILEmit->EmitCEQ();
227
228     EmitStoreManagedValue(pslILEmit);
229 }    
230
231
232 LocalDesc ILWSTRMarshaler::GetNativeType()
233 {
234     LIMITED_METHOD_CONTRACT;
235
236     //
237     // pointer to value class
238     //
239     return LocalDesc(ELEMENT_TYPE_I);
240 }
241
242 LocalDesc ILWSTRMarshaler::GetManagedType()
243 {
244     LIMITED_METHOD_CONTRACT;
245
246     //
247     // value class
248     //
249     return LocalDesc(ELEMENT_TYPE_STRING);
250 }
251
252 void ILWSTRMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
253 {
254     LIMITED_METHOD_CONTRACT;
255     UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
256 }
257
258 void ILWSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
259 {
260     LIMITED_METHOD_CONTRACT;
261     UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
262 }
263
264 void ILWSTRMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
265 {
266     LIMITED_METHOD_CONTRACT;
267     UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
268 }    
269
270 void ILWSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
271 {
272     LIMITED_METHOD_CONTRACT;
273     UNREACHABLE_MSG("Should be in-only and all other paths are covered by the EmitConvertSpaceAndContents* paths");
274 }    
275
276 bool ILWSTRMarshaler::NeedsClearNative()
277 {
278     LIMITED_METHOD_CONTRACT;
279
280     // will evaluate to true iff there is something CoTaskMemAlloc'ed that we need to free
281     bool needsClear = (IsByref(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags)) || IsRetval(m_dwMarshalFlags);
282     
283     // m_fCoMemoryAllocated => needsClear
284     // (if we allocated the memory, we will free it; for byref [out] and retval we free memory allocated by the callee)
285     _ASSERTE(!m_fCoMemoryAllocated || needsClear);
286
287     return needsClear;
288 }
289
290 void ILWSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
291 {
292     STANDARD_VM_CONTRACT;
293
294     EmitLoadNativeValue(pslILEmit);
295     // static void CoTaskMemFree(IntPtr ptr)
296     pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
297 }
298
299 void ILWSTRMarshaler::EmitClearNativeTemp(ILCodeStream* pslILEmit)
300 {
301     LIMITED_METHOD_CONTRACT;
302     UNREACHABLE_MSG("The string is either pinned or a copy is stack-allocated, NeedsClearNative should have returned false");
303 }
304
305 bool ILWSTRMarshaler::CanUsePinnedManagedString(DWORD dwMarshalFlags)
306 {
307     LIMITED_METHOD_CONTRACT;
308     return IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && !IsOut(dwMarshalFlags);
309 }
310
311 //
312 // input stack:  0: managed string
313 // output stack: 0: (string_length+1) * sizeof(WCHAR)
314 //
315 void ILWSTRMarshaler::EmitCheckManagedStringLength(ILCodeStream* pslILEmit)
316 {
317     STANDARD_VM_CONTRACT;
318
319     pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
320     pslILEmit->EmitLDC(1);
321     pslILEmit->EmitADD();
322     pslILEmit->EmitDUP();
323     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
324     pslILEmit->EmitDUP();
325     pslILEmit->EmitADD();           // (length+1) * sizeof(WCHAR)
326 }
327
328 void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNative(ILCodeStream* pslILEmit)
329 {
330     STANDARD_VM_CONTRACT;
331
332     INDEBUG(m_fCoMemoryAllocated = true);
333
334     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
335     DWORD dwLengthLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
336     
337     pslILEmit->EmitLoadNullPtr();
338     EmitStoreNativeValue(pslILEmit);
339     
340     EmitLoadManagedValue(pslILEmit);
341     pslILEmit->EmitBRFALSE(pNullRefLabel);
342     
343     EmitLoadManagedValue(pslILEmit);
344     EmitCheckManagedStringLength(pslILEmit);
345
346     // cb
347
348     pslILEmit->EmitDUP();
349     pslILEmit->EmitSTLOC(dwLengthLocalNum);
350
351     // cb
352
353     // static IntPtr AllocCoTaskMem(int cb)
354     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
355     EmitStoreNativeValue(pslILEmit);
356
357     EmitLoadManagedValue(pslILEmit);
358     EmitLoadNativeValue(pslILEmit);
359
360     // src, dst
361
362     pslILEmit->EmitLDLOC(dwLengthLocalNum); // length
363     
364     // static void System.String.InternalCopy(String src, IntPtr dest,int len)
365     pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
366     pslILEmit->EmitLabel(pNullRefLabel);
367 }
368
369 void ILWSTRMarshaler::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
370 {
371     STANDARD_VM_CONTRACT;
372
373     if (CanUsePinnedManagedString(m_dwMarshalFlags))
374     {
375         LocalDesc locDesc = GetManagedType();
376         locDesc.MakePinned();
377         DWORD dwPinnedLocal = pslILEmit->NewLocal(locDesc);
378         int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__STRING__M_FIRST_CHAR));
379         ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
380         
381         pslILEmit->EmitLoadNullPtr();
382         EmitStoreNativeValue(pslILEmit);
383
384         EmitLoadManagedValue(pslILEmit);
385         pslILEmit->EmitBRFALSE(pNullRefLabel);
386
387         EmitLoadManagedValue(pslILEmit);
388         pslILEmit->EmitSTLOC(dwPinnedLocal);
389         pslILEmit->EmitLDLOC(dwPinnedLocal);
390         pslILEmit->EmitLDFLDA(fieldDef);
391         EmitStoreNativeValue(pslILEmit);
392
393         if (g_pConfig->InteropLogArguments())
394         {
395             m_pslNDirect->EmitLogNativeArgument(pslILEmit, dwPinnedLocal);
396         }
397
398         pslILEmit->EmitLabel(pNullRefLabel);
399
400     }
401     else
402     {
403         ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
404         DWORD dwLengthLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
405         
406         pslILEmit->EmitLoadNullPtr();
407         EmitStoreNativeValue(pslILEmit);
408         
409         EmitLoadManagedValue(pslILEmit);
410         pslILEmit->EmitBRFALSE(pNullRefLabel);
411         
412         EmitLoadManagedValue(pslILEmit);
413         EmitCheckManagedStringLength(pslILEmit);
414
415         // cb
416
417         pslILEmit->EmitDUP();
418         pslILEmit->EmitSTLOC(dwLengthLocalNum);
419
420         // cb
421
422         pslILEmit->EmitLOCALLOC();              // @TODO: add a non-localloc path for large strings
423         EmitStoreNativeValue(pslILEmit);
424
425         EmitLoadManagedValue(pslILEmit);
426         EmitLoadNativeValue(pslILEmit);
427
428         // src, dst
429
430         pslILEmit->EmitLDLOC(dwLengthLocalNum); // length
431         
432         // static void System.String.InternalCopy(String src, IntPtr dest,int len)
433         pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
434         pslILEmit->EmitLabel(pNullRefLabel);
435     }
436 }
437
438 //
439 // input stack:  0: native string
440 // output stack: 0: num chars, no null
441 //
442 void ILWSTRMarshaler::EmitCheckNativeStringLength(ILCodeStream* pslILEmit)
443 {
444     STANDARD_VM_CONTRACT;
445
446     pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
447     pslILEmit->EmitDUP();
448     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
449 }
450
451 void ILWSTRMarshaler::EmitConvertSpaceAndContentsNativeToCLR(ILCodeStream* pslILEmit)
452 {
453     STANDARD_VM_CONTRACT;
454
455     ILCodeLabel* pIsNullLabelByref = pslILEmit->NewCodeLabel();
456         
457     EmitLoadNativeValue(pslILEmit);
458     pslILEmit->EmitBRFALSE(pIsNullLabelByref);
459
460     EmitLoadNativeValue(pslILEmit);
461     pslILEmit->EmitDUP();
462     EmitCheckNativeStringLength(pslILEmit);
463     pslILEmit->EmitPOP();       // pop num chars
464     
465     pslILEmit->EmitNEWOBJ(METHOD__STRING__CTOR_CHARPTR, 1);
466     EmitStoreManagedValue(pslILEmit);
467     
468     pslILEmit->EmitLabel(pIsNullLabelByref);
469 }
470
471
472 LocalDesc ILOptimizedAllocMarshaler::GetNativeType()
473 {
474     LIMITED_METHOD_CONTRACT;
475     return LocalDesc(ELEMENT_TYPE_I);
476 }
477
478 bool ILOptimizedAllocMarshaler::NeedsClearNative()
479 {
480     LIMITED_METHOD_CONTRACT;
481     return true;
482 }
483
484 void ILOptimizedAllocMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
485 {
486     STANDARD_VM_CONTRACT;
487
488     ILCodeLabel *pOptimize = NULL;
489
490     if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
491     {
492         pOptimize = pslILEmit->NewCodeLabel();
493         
494         // if (m_dwLocalBuffer) goto Optimize
495         pslILEmit->EmitLDLOC(m_dwLocalBuffer);
496         pslILEmit->EmitBRTRUE(pOptimize);
497     }
498
499     EmitLoadNativeValue(pslILEmit);
500     // static void m_idClearNative(IntPtr ptr)
501     pslILEmit->EmitCALL(m_idClearNative, 1, 0);
502
503     // Optimize:
504     if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
505     {        
506         pslILEmit->EmitLabel(pOptimize);
507     }
508 }
509
510 LocalDesc ILUTF8BufferMarshaler::GetManagedType()
511 {
512     STANDARD_VM_CONTRACT;
513     return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
514 }
515
516 void ILUTF8BufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
517 {
518     STANDARD_VM_CONTRACT;
519
520     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
521
522     pslILEmit->EmitLoadNullPtr();
523     EmitStoreNativeValue(pslILEmit);
524
525     EmitLoadManagedValue(pslILEmit);
526     pslILEmit->EmitBRFALSE(pNullRefLabel);
527
528     EmitLoadManagedValue(pslILEmit);
529     // int System.Text.StringBuilder.get_Capacity()
530     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
531     pslILEmit->EmitDUP();
532
533     // static void StubHelpers.CheckStringLength(int length)
534     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
535
536     // Max number of bytes for UTF8 string in BMP plane is ( StringBuilder.Capacity + 1 ) * 3 + 1
537     // first +1 if the high surrogate is '?' and second +1 for null byte.
538
539     // stack: capacity_in_bytes
540     pslILEmit->EmitLDC(1);
541     pslILEmit->EmitADD();
542
543     // stack: capacity
544     pslILEmit->EmitLDC(3);
545     pslILEmit->EmitMUL();
546
547     // stack: offset_of_null
548     DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
549     pslILEmit->EmitDUP();
550     pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
551
552     // make space for '\0'
553     pslILEmit->EmitLDC(1);
554     pslILEmit->EmitADD();
555
556     // stack: alloc_size_in_bytes
557     ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel();
558     if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
559     {
560         ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel();
561         m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
562
563         // LocalBuffer = 0
564         pslILEmit->EmitLoadNullPtr();
565         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
566
567         // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
568         pslILEmit->EmitDUP();
569         pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
570         pslILEmit->EmitCGT_UN();
571         pslILEmit->EmitBRTRUE(pNoOptimize);
572
573         pslILEmit->EmitLOCALLOC();
574         pslILEmit->EmitDUP();
575         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
576         pslILEmit->EmitBR(pAllocRejoin);
577
578         pslILEmit->EmitLabel(pNoOptimize);
579     }
580
581     // static IntPtr AllocCoTaskMem(int cb)
582     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
583
584     pslILEmit->EmitLabel(pAllocRejoin);
585
586     // stack: native_addr
587
588     pslILEmit->EmitDUP();
589     EmitStoreNativeValue(pslILEmit);
590
591     pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
592
593     // stack: native_addr offset_of_null
594     pslILEmit->EmitADD();
595
596     // stack: addr_of_null0    
597     pslILEmit->EmitLDC(0);
598     pslILEmit->EmitSTIND_I1();
599
600     pslILEmit->EmitLabel(pNullRefLabel);
601 }
602
603 void ILUTF8BufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
604 {
605     STANDARD_VM_CONTRACT;
606     DWORD dwUtf8MarshalFlags =
607         (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
608         (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
609
610     // setup to call UTF8BufferMarshaler.ConvertToNative
611     EmitLoadManagedValue(pslILEmit);
612     EmitLoadNativeValue(pslILEmit);
613     pslILEmit->EmitLDC(dwUtf8MarshalFlags);
614
615     //ConvertToNative(StringBuilder sb,IntPtr pNativeBuffer, int flags) 
616     pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_NATIVE, 3, 1);
617     EmitStoreNativeValue(pslILEmit);
618 }
619
620 void ILUTF8BufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
621 {
622     STANDARD_VM_CONTRACT;
623
624     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
625
626     EmitLoadNativeValue(pslILEmit);
627     pslILEmit->EmitBRFALSE(pNullRefLabel);
628
629     if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
630     {
631         EmitLoadNativeValue(pslILEmit);
632         // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
633         pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
634     }
635     else
636     {
637         // don't touch the native buffer in the native->CLR out-only case
638         pslILEmit->EmitLDC(0);
639     }
640     // Convert to UTF8 and then call 
641     // System.Text.StringBuilder..ctor(int capacity)
642     pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
643     EmitStoreManagedValue(pslILEmit);
644     pslILEmit->EmitLabel(pNullRefLabel);
645 }
646
647 void ILUTF8BufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
648 {
649     STANDARD_VM_CONTRACT;
650
651     EmitLoadManagedValue(pslILEmit);
652     EmitLoadNativeValue(pslILEmit);
653
654     //void UTF8BufferMarshaler.ConvertToManaged(StringBuilder sb, IntPtr pNative)
655     pslILEmit->EmitCALL(METHOD__UTF8BUFFERMARSHALER__CONVERT_TO_MANAGED, 2, 0);
656 }
657
658
659 LocalDesc ILWSTRBufferMarshaler::GetManagedType()
660 {
661     STANDARD_VM_CONTRACT;
662     
663     return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
664 }
665
666 void ILWSTRBufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
667 {
668     STANDARD_VM_CONTRACT;
669
670     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
671
672     pslILEmit->EmitLoadNullPtr();
673     EmitStoreNativeValue(pslILEmit);
674
675     EmitLoadManagedValue(pslILEmit);
676     pslILEmit->EmitBRFALSE(pNullRefLabel);
677
678     EmitLoadManagedValue(pslILEmit);
679     // int System.Text.StringBuilder.get_Capacity()
680     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
681     pslILEmit->EmitDUP();
682
683     // static void StubHelpers.CheckStringLength(int length)
684     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
685
686     // stack: capacity
687
688     pslILEmit->EmitLDC(2);
689     pslILEmit->EmitMUL();
690
691     // stack: capacity_in_bytes
692
693     pslILEmit->EmitLDC(2);
694     pslILEmit->EmitADD();
695
696     // stack: offset_of_secret_null
697
698     DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
699     pslILEmit->EmitDUP();
700     pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
701
702     pslILEmit->EmitLDC(2);
703     pslILEmit->EmitADD();
704
705     // stack: alloc_size_in_bytes
706     ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel(); 
707     if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
708     {
709         ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel(); 
710         m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
711
712         // LocalBuffer = 0
713         pslILEmit->EmitLoadNullPtr();
714         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
715
716         // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
717         pslILEmit->EmitDUP();
718         pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
719         pslILEmit->EmitCGT_UN();
720         pslILEmit->EmitBRTRUE(pNoOptimize);
721
722         pslILEmit->EmitLOCALLOC();
723         pslILEmit->EmitDUP();
724         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
725         pslILEmit->EmitBR(pAllocRejoin);
726
727         pslILEmit->EmitLabel(pNoOptimize);
728     }
729    
730     // static IntPtr AllocCoTaskMem(int cb)
731     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
732
733     pslILEmit->EmitLabel(pAllocRejoin);
734
735     // stack: native_addr
736
737     pslILEmit->EmitDUP();
738     EmitStoreNativeValue(pslILEmit);
739
740     pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
741
742     // stack: offset_of_secret_null  native_addr
743
744     pslILEmit->EmitADD();
745
746     // stack: addr_of_secret_null
747
748     pslILEmit->EmitLDC(0);
749
750     // stack: addr_of_secret_null  0
751
752     pslILEmit->EmitSTIND_I2();
753     pslILEmit->EmitLabel(pNullRefLabel);
754 }
755
756 void ILWSTRBufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
757 {
758     STANDARD_VM_CONTRACT;
759
760     DWORD dwTempNumBytesLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
761
762     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
763
764     EmitLoadNativeValue(pslILEmit);
765     pslILEmit->EmitBRFALSE(pNullRefLabel);
766
767     EmitLoadManagedValue(pslILEmit);
768     pslILEmit->EmitDUP();
769     
770     // stack: StringBuilder StringBuilder
771
772     // int System.Text.StringBuilder.get_Length()
773     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_LENGTH, 1, 1);
774
775     // stack: StringBuilder length
776
777     // if (!fConvertSpaceJustCalled)
778     {
779         // we don't need to double-check the length because the length
780         // must be smaller than the capacity and the capacity was already
781         // checked by EmitConvertSpaceCLRToNative
782         
783         pslILEmit->EmitDUP();
784         // static void StubHelpers.CheckStringLength(int length)
785         pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
786     }
787
788     // stack: StringBuilder length 
789
790     pslILEmit->EmitDUP();
791     pslILEmit->EmitADD();
792
793     // stack: StringBuilder cb
794
795     pslILEmit->EmitSTLOC(dwTempNumBytesLocal);
796
797     // stack: StringBuilder
798
799     EmitLoadNativeValue(pslILEmit);
800     pslILEmit->EmitLDLOC(dwTempNumBytesLocal);
801
802     // stack: stringbuilder native_buffer cb
803
804     // void System.Text.StringBuilder.InternalCopy(IntPtr dest,int len)
805     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__INTERNAL_COPY, 3, 0);
806
807     //
808     // null-terminate the native string
809     //
810     EmitLoadNativeValue(pslILEmit);
811     pslILEmit->EmitLDLOC(dwTempNumBytesLocal);
812     pslILEmit->EmitADD();
813     pslILEmit->EmitLDC(0);
814     pslILEmit->EmitSTIND_I2();
815
816     pslILEmit->EmitLabel(pNullRefLabel);
817 }
818
819 void ILWSTRBufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
820 {
821     STANDARD_VM_CONTRACT;
822
823     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
824
825     EmitLoadNativeValue(pslILEmit);
826     pslILEmit->EmitBRFALSE(pNullRefLabel);
827
828     if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
829     {
830         EmitLoadNativeValue(pslILEmit);
831         // static int System.String.wcslen(char *ptr)
832         pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
833     }
834     else
835     {
836         // don't touch the native buffer in the native->CLR out-only case
837         pslILEmit->EmitLDC(0);
838     }
839
840     // System.Text.StringBuilder..ctor(int capacity)
841     pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
842     EmitStoreManagedValue(pslILEmit);
843
844     pslILEmit->EmitLabel(pNullRefLabel);
845 }
846
847 void ILWSTRBufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
848 {
849     STANDARD_VM_CONTRACT;
850
851     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
852
853     EmitLoadNativeValue(pslILEmit);
854     pslILEmit->EmitBRFALSE(pNullRefLabel);
855
856     EmitLoadManagedValue(pslILEmit);
857     EmitLoadNativeValue(pslILEmit);
858
859     pslILEmit->EmitDUP();
860     // static int System.String.wcslen(char *ptr)
861     pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
862     
863     // void System.Text.StringBuilder.ReplaceBuffer(char* newBuffer, int newLength);
864     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__REPLACE_BUFFER_INTERNAL, 3, 0);
865     pslILEmit->EmitLabel(pNullRefLabel);
866 }        
867
868 LocalDesc ILCSTRBufferMarshaler::GetManagedType()
869 {
870     STANDARD_VM_CONTRACT;
871     
872     return LocalDesc(MscorlibBinder::GetClass(CLASS__STRING_BUILDER));
873 }
874
875 void ILCSTRBufferMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
876 {
877     STANDARD_VM_CONTRACT;
878
879     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
880
881     pslILEmit->EmitLoadNullPtr();
882     EmitStoreNativeValue(pslILEmit);
883
884     EmitLoadManagedValue(pslILEmit);
885     pslILEmit->EmitBRFALSE(pNullRefLabel);
886
887     EmitLoadManagedValue(pslILEmit);
888     // int System.Text.StringBuilder.get_Capacity()
889     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_CAPACITY, 1, 1);
890     pslILEmit->EmitDUP();
891
892     // static void StubHelpers.CheckStringLength(int length)
893     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
894
895     // stack: capacity
896
897     pslILEmit->EmitLDSFLD(pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
898     pslILEmit->EmitMUL();
899
900     // stack: capacity_in_bytes
901
902     pslILEmit->EmitLDC(1);  
903     pslILEmit->EmitADD();
904
905     // stack: offset_of_secret_null
906
907     DWORD dwTmpOffsetOfSecretNull = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
908     pslILEmit->EmitDUP();
909     pslILEmit->EmitSTLOC(dwTmpOffsetOfSecretNull); // make sure the stack is empty for localloc
910
911     pslILEmit->EmitLDC(3);
912     pslILEmit->EmitADD();
913
914     // stack: alloc_size_in_bytes
915     ILCodeLabel *pAllocRejoin = pslILEmit->NewCodeLabel(); 
916     if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
917     {
918         ILCodeLabel *pNoOptimize = pslILEmit->NewCodeLabel(); 
919         m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
920
921         // LocalBuffer = 0
922         pslILEmit->EmitLoadNullPtr();
923         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
924
925         // if (alloc_size_in_bytes > MAX_LOCAL_BUFFER_LENGTH) goto NoOptimize
926         pslILEmit->EmitDUP();
927         pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
928         pslILEmit->EmitCGT_UN();
929         pslILEmit->EmitBRTRUE(pNoOptimize);
930
931         pslILEmit->EmitLOCALLOC();
932         pslILEmit->EmitDUP();
933         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
934         pslILEmit->EmitBR(pAllocRejoin);
935
936         pslILEmit->EmitLabel(pNoOptimize);
937     }
938
939     // static IntPtr AllocCoTaskMem(int cb)
940     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
941
942     pslILEmit->EmitLabel(pAllocRejoin);
943
944     // stack: native_addr
945
946     pslILEmit->EmitDUP();
947     EmitStoreNativeValue(pslILEmit);
948
949     pslILEmit->EmitLDLOC(dwTmpOffsetOfSecretNull);
950
951     // stack: native_addr offset_of_secret_null
952
953     pslILEmit->EmitADD();
954
955     // stack: addr_of_secret_null0
956
957     pslILEmit->EmitDUP();
958     pslILEmit->EmitLDC(0);
959     pslILEmit->EmitSTIND_I1();
960
961     // stack: addr_of_secret_null0
962
963     pslILEmit->EmitDUP();
964     pslILEmit->EmitLDC(1);
965     pslILEmit->EmitADD();
966     pslILEmit->EmitLDC(0);
967     pslILEmit->EmitSTIND_I1();
968
969     // stack: addr_of_secret_null0
970
971     pslILEmit->EmitLDC(2);
972     pslILEmit->EmitADD();
973     pslILEmit->EmitLDC(0);
974     pslILEmit->EmitSTIND_I1();
975
976     pslILEmit->EmitLabel(pNullRefLabel);
977 }
978
979 void ILCSTRBufferMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
980 {
981     STANDARD_VM_CONTRACT;
982
983     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
984     DWORD dwNumBytesLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
985     DWORD dwSrcLocal = pslILEmit->NewLocal(ELEMENT_TYPE_OBJECT);
986
987     EmitLoadNativeValue(pslILEmit);
988     pslILEmit->EmitBRFALSE(pNullRefLabel);
989
990     EmitLoadManagedValue(pslILEmit);
991     // int System.Text.StringBuilder.get_Length()
992     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__GET_LENGTH, 1, 1);
993     // static void StubHelpers.CheckStringLength(int length)
994     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
995
996     EmitLoadManagedValue(pslILEmit);
997     // String System.Text.StringBuilder.ToString()
998     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__TO_STRING, 1, 1);
999     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
1000     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
1001     pslILEmit->EmitLDLOCA(dwNumBytesLocalNum);
1002
1003     // static byte[] DoAnsiConversion(string str, bool fBestFit, bool fThrowOnUnmappableChar, out int cbLength)
1004     pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__DO_ANSI_CONVERSION, 4, 1);
1005     pslILEmit->EmitSTLOC(dwSrcLocal);
1006     EmitLoadNativeValue(pslILEmit);             // pDest
1007     pslILEmit->EmitLDC(0);                      // destIndex
1008     pslILEmit->EmitLDLOC(dwSrcLocal);           // src[]
1009     pslILEmit->EmitLDC(0);                      // srcIndex
1010     pslILEmit->EmitLDLOC(dwNumBytesLocalNum);   // len
1011
1012     // static void Memcpy(byte* pDest, int destIndex, byte[] src, int srcIndex, int len)
1013     pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY_PTRBYTE_ARRBYTE, 5, 0);
1014
1015     // null terminate the string
1016     EmitLoadNativeValue(pslILEmit);
1017     pslILEmit->EmitLDLOC(dwNumBytesLocalNum);
1018     pslILEmit->EmitADD();
1019     pslILEmit->EmitLDC(0);
1020     pslILEmit->EmitSTIND_I1();
1021
1022     pslILEmit->EmitLabel(pNullRefLabel);
1023 }
1024
1025 void ILCSTRBufferMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
1026 {
1027     STANDARD_VM_CONTRACT;
1028
1029     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
1030
1031     EmitLoadNativeValue(pslILEmit);
1032     pslILEmit->EmitBRFALSE(pNullRefLabel);
1033
1034     if (IsIn(m_dwMarshalFlags) || IsCLRToNative(m_dwMarshalFlags))
1035     {
1036         EmitLoadNativeValue(pslILEmit);
1037         // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
1038         pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
1039     }
1040     else
1041     {
1042         // don't touch the native buffer in the native->CLR out-only case
1043         pslILEmit->EmitLDC(0);
1044     }
1045
1046     // System.Text.StringBuilder..ctor(int capacity)
1047     pslILEmit->EmitNEWOBJ(METHOD__STRING_BUILDER__CTOR_INT, 1);
1048     EmitStoreManagedValue(pslILEmit);
1049
1050     pslILEmit->EmitLabel(pNullRefLabel);
1051 }
1052
1053 void ILCSTRBufferMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1054 {
1055     STANDARD_VM_CONTRACT;
1056     
1057     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
1058
1059     EmitLoadNativeValue(pslILEmit);
1060     pslILEmit->EmitBRFALSE(pNullRefLabel);
1061
1062     EmitLoadManagedValue(pslILEmit);
1063     EmitLoadNativeValue(pslILEmit);
1064
1065     pslILEmit->EmitDUP();
1066     // static int System.StubHelpers.StubHelpers.strlen(sbyte* ptr)
1067     pslILEmit->EmitCALL(METHOD__STUBHELPERS__STRLEN, 1, 1);
1068     
1069     // void System.Text.StringBuilder.ReplaceBuffer(sbyte* newBuffer, int newLength);
1070     pslILEmit->EmitCALL(METHOD__STRING_BUILDER__REPLACE_BUFFER_ANSI_INTERNAL, 3, 0);
1071
1072     pslILEmit->EmitLabel(pNullRefLabel);
1073 }        
1074
1075
1076
1077 LocalDesc ILValueClassMarshaler::GetNativeType()
1078 {
1079     STANDARD_VM_CONTRACT;
1080
1081     return LocalDesc(TypeHandle(m_pargs->m_pMT).MakeNativeValueType());
1082 }
1083
1084 LocalDesc ILValueClassMarshaler::GetManagedType()
1085 {
1086     LIMITED_METHOD_CONTRACT;
1087     
1088     return LocalDesc(m_pargs->m_pMT);
1089 }
1090
1091 void ILValueClassMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
1092 {
1093     STANDARD_VM_CONTRACT;
1094     
1095     EmitLoadNativeHomeAddr(pslILEmit);
1096     pslILEmit->EmitINITOBJ(pslILEmit->GetToken(TypeHandle(m_pargs->m_pMT).MakeNativeValueType()));
1097 }
1098
1099 bool ILValueClassMarshaler::NeedsClearNative()
1100 {
1101     return true;
1102 }
1103
1104 void ILValueClassMarshaler::EmitClearNative(ILCodeStream * pslILEmit)
1105 {
1106     STANDARD_VM_CONTRACT;
1107
1108     mdToken     managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
1109     
1110     EmitLoadNativeHomeAddr(pslILEmit);
1111     pslILEmit->EmitLDTOKEN(managedVCToken); // pMT
1112     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1113     pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CLEAR_NATIVE, 2, 0);
1114 }
1115
1116
1117 void ILValueClassMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1118 {
1119     STANDARD_VM_CONTRACT;
1120
1121     mdToken     managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
1122
1123     EmitLoadNativeHomeAddr(pslILEmit);      // dst
1124     EmitLoadManagedHomeAddr(pslILEmit);     // src
1125     pslILEmit->EmitLDTOKEN(managedVCToken); // pMT
1126     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1); // Convert RTH to IntPtr
1127
1128     m_pslNDirect->LoadCleanupWorkList(pslILEmit);
1129     pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CONVERT_TO_NATIVE, 4, 0);        // void ConvertToNative(IntPtr dst, IntPtr src, IntPtr pMT, ref CleanupWorkListElement pCleanupWorkList)
1130 }
1131
1132 void ILValueClassMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1133 {
1134     STANDARD_VM_CONTRACT;
1135
1136     mdToken     managedVCToken = pslILEmit->GetToken(m_pargs->m_pMT);
1137
1138     EmitLoadManagedHomeAddr(pslILEmit);     // dst
1139     EmitLoadNativeHomeAddr(pslILEmit);      // src
1140     pslILEmit->EmitLDTOKEN(managedVCToken);                                 // pMT
1141     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1142     pslILEmit->EmitCALL(METHOD__VALUECLASSMARSHALER__CONVERT_TO_MANAGED, 3, 0);   // void ConvertToManaged(IntPtr dst, IntPtr src, IntPtr pMT)
1143 }
1144
1145
1146 #ifdef FEATURE_COMINTEROP
1147 LocalDesc ILObjectMarshaler::GetNativeType()
1148 {
1149     STANDARD_VM_CONTRACT;
1150
1151     return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__NATIVEVARIANT)));
1152 }
1153
1154 LocalDesc ILObjectMarshaler::GetManagedType()
1155 {
1156     LIMITED_METHOD_CONTRACT;
1157     
1158     return LocalDesc(ELEMENT_TYPE_OBJECT);
1159 }
1160
1161 void ILObjectMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1162 {
1163     STANDARD_VM_CONTRACT;
1164
1165     if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
1166     {
1167         // Keep the VARIANT as it is - the stubhelper will do a VT_BYREF check on it.
1168     }
1169     else
1170     {
1171         // V_VT(pDest) = VT_EMPTY
1172         EmitReInitNative(pslILEmit);
1173     }
1174
1175     EmitLoadManagedValue(pslILEmit);                        // load src
1176     EmitLoadNativeHomeAddr(pslILEmit);                      // load dst
1177     pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CONVERT_TO_NATIVE, 2, 0); // void ConvertToNative(object objSrc, IntPtr pDstVariant)
1178 }
1179
1180 void ILObjectMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1181 {
1182     STANDARD_VM_CONTRACT;
1183
1184     EmitLoadNativeHomeAddr(pslILEmit);
1185     pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CONVERT_TO_MANAGED, 1, 1);  // object ConvertToManaged(IntPtr pSrcVariant);
1186     EmitStoreManagedValue(pslILEmit);
1187 }    
1188
1189 bool ILObjectMarshaler::NeedsClearNative()
1190 {
1191     LIMITED_METHOD_CONTRACT;
1192     return true;
1193 }
1194
1195 void ILObjectMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
1196 {
1197     STANDARD_VM_CONTRACT;
1198     
1199     if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
1200     {
1201         // We don't want to clear variants passed from native by-ref here as we
1202         // want to be able to detect the VT_BYREF case during backpropagation.
1203
1204         // @TODO: We shouldn't be skipping the call if pslILEmit is ILStubLinker::kExceptionCleanup
1205         // because we always want to do real cleanup in this stream.
1206     }
1207     else
1208     {
1209         EmitLoadNativeHomeAddr(pslILEmit);
1210         pslILEmit->EmitCALL(METHOD__OBJECTMARSHALER__CLEAR_NATIVE, 1, 0);
1211     }
1212 }
1213
1214 void ILObjectMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
1215 {
1216     CONTRACTL
1217     {
1218         STANDARD_VM_CHECK;
1219         CONSISTENCY_CHECK(offsetof(VARIANT, vt) == 0);
1220     }
1221     CONTRACTL_END;
1222
1223     if (!IsCLRToNative(m_dwMarshalFlags) && IsByref(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
1224     {
1225         // We don't want to clear variants passed from native by-ref here as we
1226         // want to be able to detect the VT_BYREF case during backpropagation.
1227     }
1228     else
1229     {
1230         EmitLoadNativeHomeAddr(pslILEmit);
1231         pslILEmit->EmitLDC(VT_EMPTY);
1232         pslILEmit->EmitSTIND_I2();
1233     }
1234 }
1235 #endif // FEATURE_COMINTEROP
1236
1237 LocalDesc ILDateMarshaler::GetNativeType()
1238 {
1239     LIMITED_METHOD_CONTRACT;
1240
1241     return LocalDesc(ELEMENT_TYPE_R8);
1242 }
1243
1244 LocalDesc ILDateMarshaler::GetManagedType()
1245 {
1246     STANDARD_VM_CONTRACT;
1247     
1248     return LocalDesc(MscorlibBinder::GetClass(CLASS__DATE_TIME));
1249 }
1250
1251 void ILDateMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1252 {
1253     STANDARD_VM_CONTRACT;
1254
1255     EmitLoadManagedValue(pslILEmit);
1256     // double ConvertToNative(INT64 managedDate)
1257     pslILEmit->EmitCALL(METHOD__DATEMARSHALER__CONVERT_TO_NATIVE, 1, 1); 
1258     EmitStoreNativeValue(pslILEmit);
1259 }
1260
1261 void ILDateMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1262 {
1263     STANDARD_VM_CONTRACT;
1264
1265     // will call DateTime constructor on managed home
1266     EmitLoadManagedHomeAddr(pslILEmit);
1267
1268     EmitLoadNativeValue(pslILEmit);
1269     // long ConvertToNative(double nativeData)
1270     pslILEmit->EmitCALL(METHOD__DATEMARSHALER__CONVERT_TO_MANAGED, 1, 1);
1271     
1272     pslILEmit->EmitCALL(METHOD__DATE_TIME__LONG_CTOR, 2, 0);
1273 }
1274
1275 void ILDateMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
1276 {
1277     STANDARD_VM_CONTRACT;
1278
1279     // ldc.i4.0, conv.r8 is shorter than ldc.r8 0.0
1280     pslILEmit->EmitLDC(0);
1281     pslILEmit->EmitCONV_R8();
1282     EmitStoreNativeValue(pslILEmit);
1283 }
1284
1285 LocalDesc ILCurrencyMarshaler::GetNativeType()
1286 {
1287     STANDARD_VM_CONTRACT;
1288
1289     return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY)));
1290 }
1291
1292 LocalDesc ILCurrencyMarshaler::GetManagedType()
1293 {
1294     STANDARD_VM_CONTRACT;
1295     
1296     return LocalDesc(TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)));
1297 }
1298
1299
1300 void ILCurrencyMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
1301 {
1302     STANDARD_VM_CONTRACT;
1303
1304     EmitLoadNativeHomeAddr(pslILEmit);
1305     pslILEmit->EmitINITOBJ(pslILEmit->GetToken(TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY))));
1306 }
1307
1308 void ILCurrencyMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1309 {
1310     STANDARD_VM_CONTRACT;
1311
1312     EmitLoadNativeHomeAddr(pslILEmit);
1313     EmitLoadManagedValue(pslILEmit);
1314
1315     pslILEmit->EmitCALL(METHOD__CURRENCY__DECIMAL_CTOR, 2, 0);
1316 }
1317
1318 void ILCurrencyMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1319 {
1320     STANDARD_VM_CONTRACT;
1321
1322     EmitLoadManagedHomeAddr(pslILEmit);
1323     EmitLoadNativeValue(pslILEmit);
1324
1325     pslILEmit->EmitCALL(METHOD__DECIMAL__CURRENCY_CTOR, 2, 0);
1326 }    
1327
1328
1329 #ifdef FEATURE_COMINTEROP
1330 LocalDesc ILInterfaceMarshaler::GetNativeType()
1331 {
1332     LIMITED_METHOD_CONTRACT;
1333
1334     return LocalDesc(ELEMENT_TYPE_I);
1335 }
1336
1337 LocalDesc ILInterfaceMarshaler::GetManagedType()
1338 {
1339     LIMITED_METHOD_CONTRACT;
1340     
1341     return LocalDesc(ELEMENT_TYPE_OBJECT);
1342 }
1343
1344 void ILInterfaceMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1345 {
1346     STANDARD_VM_CONTRACT;
1347
1348     ItfMarshalInfo itfInfo;
1349     m_pargs->m_pMarshalInfo->GetItfMarshalInfo(&itfInfo);
1350
1351     EmitLoadManagedValue(pslILEmit);
1352     
1353     if (itfInfo.thNativeItf.GetMethodTable())
1354     {
1355         pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thNativeItf.GetMethodTable()));
1356         pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1357     }
1358     else
1359     {
1360         pslILEmit->EmitLoadNullPtr();
1361     }
1362     
1363     if (itfInfo.thClass.GetMethodTable())
1364     {
1365         pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
1366         pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1367     }
1368     else
1369     {
1370         pslILEmit->EmitLoadNullPtr();
1371     }
1372     pslILEmit->EmitLDC(itfInfo.dwFlags);
1373
1374     // static IntPtr ConvertToNative(object objSrc, IntPtr itfMT, IntPtr classMT, int flags);
1375     pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CONVERT_TO_NATIVE, 4, 1);
1376
1377     EmitStoreNativeValue(pslILEmit);
1378
1379     if (IsCLRToNative(m_dwMarshalFlags) && 
1380         m_pargs->m_pMarshalInfo->IsWinRTScenario())
1381     {    
1382         // If we are calling from CLR into WinRT and we are passing an interface to WinRT, we need to
1383         // keep the object alive across unmanaged call because Jupiter might need to add this
1384         // RCW into their live tree and whatever CCWs referenced by this RCW could get collected
1385         // before the call to native, for example:
1386         //
1387         // Button btn = new Button();
1388         // btn.OnClick += ...
1389         // m_grid.Children.Add(btn)
1390         //
1391         // In this case, btn could be collected and takes the delegate CCW with it, before Children.add 
1392         // native method is called, and as a result Jupiter will add the neutered CCW into the tree
1393         //
1394         // The fix is to extend the lifetime of the argument across the call to native by doing a GC.KeepAlive
1395         // keep the delegate ref alive across the call-out to native
1396         EmitLoadManagedValue(m_pcsUnmarshal);
1397         m_pcsUnmarshal->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
1398     }
1399 }
1400
1401 void ILInterfaceMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1402 {
1403     STANDARD_VM_CONTRACT;
1404
1405     ItfMarshalInfo itfInfo;
1406     m_pargs->m_pMarshalInfo->GetItfMarshalInfo(&itfInfo);
1407
1408     // the helper may assign NULL to the home (see below)
1409     EmitLoadNativeHomeAddr(pslILEmit);
1410     
1411     if (IsCLRToNative(m_dwMarshalFlags) && m_pargs->m_pMarshalInfo->IsWinRTScenario())
1412     {
1413         // We are converting an interface pointer to object in a CLR->native stub which means
1414         // that the interface pointer has been AddRef'ed for us by the callee. If we end up
1415         // wrapping it with a new RCW, we can omit another AddRef/Release pair. Note that if
1416         // a new RCW is created the native home will be zeroed out by the helper so the call
1417         // to InterfaceMarshaler__ClearNative will become a no-op.
1418
1419         // Note that we are only doing this for WinRT scenarios to reduce the risk of this change
1420         itfInfo.dwFlags |= ItfMarshalInfo::ITF_MARSHAL_SUPPRESS_ADDREF;
1421     }
1422
1423     if (itfInfo.thItf.GetMethodTable())
1424     {
1425         pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thItf.GetMethodTable()));
1426         pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1427     }
1428     else
1429     {
1430         pslILEmit->EmitLoadNullPtr();
1431     }
1432     
1433     if (itfInfo.thClass.GetMethodTable())
1434     {
1435         pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(itfInfo.thClass.GetMethodTable()));
1436         pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
1437     }
1438     else
1439     {
1440         pslILEmit->EmitLoadNullPtr();
1441     }
1442     pslILEmit->EmitLDC(itfInfo.dwFlags);
1443     
1444     // static object ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, int flags);
1445     pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CONVERT_TO_MANAGED, 4, 1);
1446     
1447     EmitStoreManagedValue(pslILEmit);
1448 }    
1449
1450 bool ILInterfaceMarshaler::NeedsClearNative()
1451 {
1452     LIMITED_METHOD_CONTRACT;
1453     return true;
1454 }
1455
1456 void ILMarshaler::EmitInterfaceClearNative(ILCodeStream* pslILEmit)
1457 {
1458     STANDARD_VM_CONTRACT;
1459
1460     ILCodeLabel *pSkipClearNativeLabel = pslILEmit->NewCodeLabel();
1461     EmitLoadNativeValue(pslILEmit);
1462     pslILEmit->EmitBRFALSE(pSkipClearNativeLabel);
1463     EmitLoadNativeValue(pslILEmit);
1464     // static void ClearNative(IntPtr pUnk);
1465     pslILEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
1466     pslILEmit->EmitLabel(pSkipClearNativeLabel);
1467 }
1468
1469 void ILInterfaceMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
1470 {
1471     STANDARD_VM_CONTRACT;
1472     EmitInterfaceClearNative(pslILEmit);
1473 }
1474 #endif // FEATURE_COMINTEROP
1475
1476
1477 LocalDesc ILAnsiCharMarshaler::GetNativeType()
1478 {
1479     LIMITED_METHOD_CONTRACT;
1480
1481     return LocalDesc(ELEMENT_TYPE_U1);
1482 }
1483
1484 LocalDesc ILAnsiCharMarshaler::GetManagedType()
1485 {
1486     LIMITED_METHOD_CONTRACT;
1487     
1488     return LocalDesc(ELEMENT_TYPE_CHAR);
1489 }
1490
1491 void ILAnsiCharMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1492 {
1493     STANDARD_VM_CONTRACT;
1494
1495     EmitLoadManagedValue(pslILEmit);
1496     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
1497     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
1498     pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__CONVERT_TO_NATIVE, 3, 1);
1499     EmitStoreNativeValue(pslILEmit);
1500 }
1501
1502 void ILAnsiCharMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1503 {
1504     STANDARD_VM_CONTRACT;
1505
1506     EmitLoadNativeValue(pslILEmit);
1507     pslILEmit->EmitCALL(METHOD__ANSICHARMARSHALER__CONVERT_TO_MANAGED, 1, 1);
1508     EmitStoreManagedValue(pslILEmit);
1509 }    
1510
1511 #ifdef FEATURE_COMINTEROP
1512 LocalDesc ILOleColorMarshaler::GetNativeType()
1513 {
1514     LIMITED_METHOD_CONTRACT;
1515
1516     return LocalDesc(ELEMENT_TYPE_I4);
1517 }
1518
1519 LocalDesc ILOleColorMarshaler::GetManagedType()
1520 {
1521     STANDARD_VM_CONTRACT;
1522
1523     BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
1524     TypeHandle  hndColorType = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
1525
1526     //
1527     // value class
1528     //
1529     return LocalDesc(hndColorType); // System.Drawing.Color
1530 }
1531
1532 void ILOleColorMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1533 {
1534     STANDARD_VM_CONTRACT;
1535
1536     BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
1537     MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
1538
1539     EmitLoadManagedValue(pslILEmit);
1540     // int System.Drawing.ColorTranslator.ToOle(System.Drawing.Color c)
1541     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
1542     EmitStoreNativeValue(pslILEmit);
1543 }
1544
1545 void ILOleColorMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1546 {
1547     STANDARD_VM_CONTRACT;
1548
1549     BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
1550     MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
1551
1552     EmitLoadNativeValue(pslILEmit);
1553     // System.Drawing.Color System.Drawing.ColorTranslator.FromOle(int oleColor)
1554     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
1555     EmitStoreManagedValue(pslILEmit);
1556 }    
1557
1558 bool ILVBByValStrWMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
1559 {
1560     LIMITED_METHOD_CONTRACT;
1561     if (IsCLRToNative(dwMarshalFlags) && IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
1562     {
1563         return true;
1564     }
1565     
1566     *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
1567     return false;
1568 }
1569
1570 bool ILVBByValStrWMarshaler::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
1571 {
1572     LIMITED_METHOD_CONTRACT;
1573     *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
1574     return false;
1575 }
1576
1577 LocalDesc ILVBByValStrWMarshaler::GetNativeType()
1578 {
1579     LIMITED_METHOD_CONTRACT;
1580     
1581     return LocalDesc(ELEMENT_TYPE_I); // BSTR
1582 }
1583
1584 LocalDesc ILVBByValStrWMarshaler::GetManagedType()
1585 {
1586     LIMITED_METHOD_CONTRACT;
1587     
1588     return LocalDesc(ELEMENT_TYPE_STRING);
1589 }
1590
1591 bool ILVBByValStrWMarshaler::IsNativePassedByRef()
1592 {
1593     LIMITED_METHOD_CONTRACT;
1594     return false;
1595 }
1596
1597 void ILVBByValStrWMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1598 {
1599     STANDARD_VM_CONTRACT;
1600
1601     ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
1602     m_dwLocalBuffer = pcsSetup->NewLocal(ELEMENT_TYPE_I);
1603     pcsSetup->EmitLoadNullPtr();
1604     pcsSetup->EmitSTLOC(m_dwLocalBuffer);
1605
1606
1607     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
1608     m_dwCCHLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
1609     DWORD dwNumBytesLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
1610
1611     pslILEmit->EmitLoadNullPtr();
1612     EmitStoreNativeValue(pslILEmit);
1613     
1614     EmitLoadManagedValue(pslILEmit);
1615     pslILEmit->EmitBRFALSE(pNullRefLabel);
1616
1617     EmitLoadManagedValue(pslILEmit);
1618     pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
1619     pslILEmit->EmitDUP();
1620     pslILEmit->EmitSTLOC(m_dwCCHLocal);
1621
1622     // cch
1623     
1624     pslILEmit->EmitLDC(1);
1625     pslILEmit->EmitADD();
1626     pslILEmit->EmitDUP();
1627     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
1628     pslILEmit->EmitDUP();
1629     pslILEmit->EmitADD();           // (length+1) * sizeof(WCHAR)
1630     pslILEmit->EmitDUP();
1631     pslILEmit->EmitSTLOC(dwNumBytesLocal);      // len <- doesn't include size of the DWORD preceeding the string
1632     pslILEmit->EmitLDC(sizeof(DWORD));
1633     pslILEmit->EmitADD();           // (length+1) * sizeof(WCHAR) + sizeof(DWORD)
1634
1635     // cb
1636
1637     ILCodeLabel* pNoOptimizeLabel = pslILEmit->NewCodeLabel();
1638     ILCodeLabel* pAllocRejoinLabel = pslILEmit->NewCodeLabel();
1639     pslILEmit->EmitDUP();
1640     pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
1641     pslILEmit->EmitCGT_UN();
1642     pslILEmit->EmitBRTRUE(pNoOptimizeLabel);
1643
1644     pslILEmit->EmitLOCALLOC();
1645     pslILEmit->EmitBR(pAllocRejoinLabel);
1646
1647     pslILEmit->EmitLabel(pNoOptimizeLabel);
1648     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
1649     pslILEmit->EmitDUP();
1650     pslILEmit->EmitSTLOC(m_dwLocalBuffer);
1651
1652     pslILEmit->EmitLabel(pAllocRejoinLabel);
1653     pslILEmit->EmitDUP();
1654     pslILEmit->EmitLDLOC(m_dwCCHLocal);
1655     pslILEmit->EmitSTIND_I4();
1656     pslILEmit->EmitLDC(sizeof(DWORD));
1657     pslILEmit->EmitADD();
1658     EmitStoreNativeValue(pslILEmit);
1659
1660     // <emtpy>
1661
1662     EmitLoadManagedValue(pslILEmit);        // src
1663     EmitLoadNativeValue(pslILEmit);         // dest
1664     pslILEmit->EmitLDLOC(dwNumBytesLocal);  // len
1665
1666     // static void System.String.InternalCopy(String src, IntPtr dest,int len)
1667     pslILEmit->EmitCALL(METHOD__STRING__INTERNAL_COPY, 3, 0);
1668
1669     pslILEmit->EmitLabel(pNullRefLabel);
1670 }
1671
1672 void ILVBByValStrWMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1673 {
1674     STANDARD_VM_CONTRACT;
1675
1676     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
1677     EmitLoadNativeValue(pslILEmit);
1678     pslILEmit->EmitBRFALSE(pNullRefLabel);
1679
1680     pslILEmit->EmitLDNULL();            // this
1681     EmitLoadNativeValue(pslILEmit);     // ptr
1682     pslILEmit->EmitLDC(0);              // startIndex
1683     pslILEmit->EmitLDLOC(m_dwCCHLocal); // length
1684
1685     // String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
1686     // TODO Phase5: Why do we call this weirdo?
1687     pslILEmit->EmitCALL(METHOD__STRING__CTORF_CHARPTR_START_LEN, 4, 1);
1688
1689     EmitStoreManagedValue(pslILEmit);
1690     pslILEmit->EmitLabel(pNullRefLabel);
1691 }
1692
1693
1694 bool ILVBByValStrWMarshaler::NeedsClearNative()
1695 {
1696     LIMITED_METHOD_CONTRACT;
1697     return true;
1698 }
1699
1700 void ILVBByValStrWMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
1701 {                
1702     STANDARD_VM_CONTRACT;
1703
1704     ILCodeLabel* pExitLabel = pslILEmit->NewCodeLabel();
1705     pslILEmit->EmitLDLOC(m_dwLocalBuffer);
1706     pslILEmit->EmitBRFALSE(pExitLabel);
1707     pslILEmit->EmitLDLOC(m_dwLocalBuffer);
1708     pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
1709     pslILEmit->EmitLabel(pExitLabel);
1710 }
1711
1712
1713 bool ILVBByValStrMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
1714 {
1715     if (IsCLRToNative(dwMarshalFlags) && IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
1716     {
1717         return true;
1718     }
1719     
1720     *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
1721     return false;
1722 }
1723
1724 bool ILVBByValStrMarshaler::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
1725 {
1726     *pErrorResID = IDS_EE_BADMARSHAL_VBBYVALSTRRESTRICTION;
1727     return false;
1728 }
1729
1730 LocalDesc ILVBByValStrMarshaler::GetNativeType()
1731 {
1732     LIMITED_METHOD_CONTRACT;
1733     
1734     return LocalDesc(ELEMENT_TYPE_I); // BSTR
1735 }
1736
1737 LocalDesc ILVBByValStrMarshaler::GetManagedType()
1738 {
1739     LIMITED_METHOD_CONTRACT;
1740     
1741     return LocalDesc(ELEMENT_TYPE_STRING);
1742 }
1743
1744 bool ILVBByValStrMarshaler::IsNativePassedByRef()
1745 {
1746     LIMITED_METHOD_CONTRACT;
1747     return false;
1748 }
1749
1750 void ILVBByValStrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1751 {
1752     STANDARD_VM_CONTRACT;
1753
1754     m_dwCCHLocal = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
1755
1756     EmitLoadManagedValue(pslILEmit);
1757     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetBestFitMapping());
1758     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar());
1759     pslILEmit->EmitLDLOCA(m_dwCCHLocal);
1760
1761     // static IntPtr ConvertToNative(string strManaged, bool fBestFit, bool fThrowOnUnmappableChar, ref int cch)
1762     pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CONVERT_TO_NATIVE, 4, 1);
1763
1764     EmitStoreNativeValue(pslILEmit);
1765 }
1766
1767 void ILVBByValStrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1768 {
1769     STANDARD_VM_CONTRACT;
1770
1771     EmitLoadNativeValue(pslILEmit);     // pNative
1772     pslILEmit->EmitLDLOC(m_dwCCHLocal); // cch
1773
1774     // static string ConvertToManaged(IntPtr pNative, int cch)
1775     pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CONVERT_TO_MANAGED, 2, 1);
1776
1777     EmitStoreManagedValue(pslILEmit);
1778 }
1779
1780 bool ILVBByValStrMarshaler::NeedsClearNative()
1781 {
1782     LIMITED_METHOD_CONTRACT;
1783     return true;
1784 }
1785
1786 void ILVBByValStrMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
1787 {
1788     STANDARD_VM_CONTRACT;
1789
1790     EmitLoadNativeValue(pslILEmit);     // pNative
1791
1792     // static void ClearNative(IntPtr pNative);
1793     pslILEmit->EmitCALL(METHOD__VBBYVALSTRMARSHALER__CLEAR_NATIVE, 1, 0);
1794 }
1795 #endif // FEATURE_COMINTEROP
1796
1797 LocalDesc ILBSTRMarshaler::GetManagedType()
1798 {
1799     LIMITED_METHOD_CONTRACT;
1800     
1801     return LocalDesc(ELEMENT_TYPE_STRING);
1802 }
1803
1804 void ILBSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1805 {
1806     STANDARD_VM_CONTRACT;
1807     
1808     ILCodeLabel* pRejoinLabel = pslILEmit->NewCodeLabel();
1809
1810     EmitLoadManagedValue(pslILEmit);
1811     
1812     if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags))
1813     {
1814         ILCodeLabel *pNoOptimizeLabel = pslILEmit->NewCodeLabel(); 
1815         m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
1816
1817         // LocalBuffer = 0
1818         pslILEmit->EmitLoadNullPtr();
1819         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
1820
1821         pslILEmit->EmitDUP();
1822         pslILEmit->EmitBRFALSE(pNoOptimizeLabel);
1823
1824         // String.Length
1825         pslILEmit->EmitDUP();
1826         pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
1827
1828         // if (length > (MAX_LOCAL_BUFFER_LENGTH - 6) / 2) goto NoOptimize
1829         pslILEmit->EmitLDC((MAX_LOCAL_BUFFER_LENGTH - 6) / 2); // number of Unicode characters - terminator - length dword
1830         pslILEmit->EmitCGT_UN();
1831         pslILEmit->EmitBRTRUE(pNoOptimizeLabel);
1832
1833         // LocalBuffer = localloc[(String.Length * 2) + 6]
1834         pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
1835         pslILEmit->EmitLDC(2);
1836         pslILEmit->EmitMUL();
1837         pslILEmit->EmitLDC(7); // + length (4B) + terminator (2B) + possible trailing byte (1B)
1838         pslILEmit->EmitADD();
1839
1840 #ifdef _DEBUG
1841         // Save the buffer length
1842         DWORD dwTmpAllocSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
1843         pslILEmit->EmitDUP();
1844         pslILEmit->EmitSTLOC(dwTmpAllocSize);
1845 #endif // _DEBUG
1846
1847         pslILEmit->EmitLOCALLOC();
1848
1849 #ifdef _DEBUG
1850         // Pass buffer length in the first DWORD so the helper is able to assert that
1851         // the buffer is large enough.
1852         pslILEmit->EmitDUP();
1853         pslILEmit->EmitLDLOC(dwTmpAllocSize);
1854         pslILEmit->EmitSTIND_I4();
1855 #endif // _DEBUG
1856
1857         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
1858
1859         // load string and LocalBuffer
1860         EmitLoadManagedValue(pslILEmit);
1861         pslILEmit->EmitLDLOC(m_dwLocalBuffer);
1862         pslILEmit->EmitBR(pRejoinLabel);
1863
1864         pslILEmit->EmitLabel(pNoOptimizeLabel);
1865     }
1866     pslILEmit->EmitLoadNullPtr();
1867
1868     pslILEmit->EmitLabel(pRejoinLabel);
1869     pslILEmit->EmitCALL(METHOD__BSTRMARSHALER__CONVERT_TO_NATIVE, 2, 1);
1870     EmitStoreNativeValue(pslILEmit);
1871 }
1872
1873 void ILBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1874 {
1875     STANDARD_VM_CONTRACT;
1876     
1877     EmitLoadNativeValue(pslILEmit);
1878     pslILEmit->EmitCALL(METHOD__BSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
1879     EmitStoreManagedValue(pslILEmit);
1880 }
1881
1882 LocalDesc ILAnsiBSTRMarshaler::GetNativeType()
1883 {
1884     LIMITED_METHOD_CONTRACT;
1885     
1886     return LocalDesc(ELEMENT_TYPE_I); // BSTR
1887 }
1888
1889 LocalDesc ILAnsiBSTRMarshaler::GetManagedType()
1890 {
1891     LIMITED_METHOD_CONTRACT;
1892     
1893     return LocalDesc(ELEMENT_TYPE_STRING);
1894 }
1895
1896 void ILAnsiBSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1897 {
1898     STANDARD_VM_CONTRACT;
1899
1900     DWORD dwAnsiMarshalFlags = 
1901         (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) | 
1902         (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
1903     
1904     pslILEmit->EmitLDC(dwAnsiMarshalFlags);
1905     EmitLoadManagedValue(pslILEmit);
1906     pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CONVERT_TO_NATIVE, 2, 1);
1907     EmitStoreNativeValue(pslILEmit);
1908 }
1909
1910 void ILAnsiBSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
1911 {
1912     STANDARD_VM_CONTRACT;
1913
1914     EmitLoadNativeValue(pslILEmit);
1915     pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
1916     EmitStoreManagedValue(pslILEmit);
1917 }
1918
1919 bool ILAnsiBSTRMarshaler::NeedsClearNative()
1920 {
1921     LIMITED_METHOD_CONTRACT;
1922     return true;
1923 }
1924
1925 void ILAnsiBSTRMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
1926 {
1927     STANDARD_VM_CONTRACT;
1928     
1929     EmitLoadNativeValue(pslILEmit);
1930     pslILEmit->EmitCALL(METHOD__ANSIBSTRMARSHALER__CLEAR_NATIVE, 1, 0);
1931 }
1932
1933 #ifdef FEATURE_COMINTEROP
1934
1935 LocalDesc ILHSTRINGMarshaler::GetNativeType()
1936 {
1937     LIMITED_METHOD_CONTRACT;
1938     return LocalDesc(ELEMENT_TYPE_I);   // HSTRING
1939 }
1940
1941 LocalDesc ILHSTRINGMarshaler::GetManagedType()
1942 {
1943     LIMITED_METHOD_CONTRACT;
1944     return LocalDesc(ELEMENT_TYPE_STRING);
1945 }
1946
1947 bool ILHSTRINGMarshaler::NeedsClearNative()
1948 {
1949     LIMITED_METHOD_CONTRACT;
1950     return true;
1951 }
1952
1953 void ILHSTRINGMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
1954 {
1955     CONTRACTL
1956     {
1957         STANDARD_VM_CHECK;
1958         PRECONDITION(CheckPointer(pslILEmit));
1959     }
1960     CONTRACTL_END;
1961
1962     // If we're only going into native code, then we can optimize and create a HSTRING reference over
1963     // the pinned System.String.  However, if the parameter will remain in native code as an out
1964     // value, then we need to create a real HSTRING.
1965     if (!IsOut(m_dwMarshalFlags) && !IsRetval(m_dwMarshalFlags))
1966     {
1967         EmitConvertCLRToHSTRINGReference(pslILEmit);
1968     }
1969     else
1970     {
1971         EmitConvertCLRToHSTRING(pslILEmit);
1972     }
1973 }
1974
1975 void ILHSTRINGMarshaler::EmitConvertCLRToHSTRINGReference(ILCodeStream* pslILEmit)
1976 {
1977     CONTRACTL
1978     {
1979         STANDARD_VM_CHECK;
1980         PRECONDITION(CheckPointer(pslILEmit));
1981         PRECONDITION(!IsOut(m_dwMarshalFlags));
1982         PRECONDITION(!IsRetval(m_dwMarshalFlags));
1983     }
1984     CONTRACTL_END;
1985
1986     //
1987     // The general strategy for fast path marshaling a short lived System.String -> HSTRING is:
1988     //      1. Pin the System.String
1989     //      2. Create an HSTRING Reference over the pinned string
1990     //      3. Pass that reference to native code
1991     //
1992
1993     // Local to hold the HSTRING_HEADER of the HSTRING reference
1994     MethodTable *pHStringHeaderMT = MscorlibBinder::GetClass(CLASS__HSTRING_HEADER_MANAGED);
1995     DWORD dwHStringHeaderLocal = pslILEmit->NewLocal(pHStringHeaderMT);
1996
1997     // Local to hold the pinned input string
1998     LocalDesc pinnedStringDesc = GetManagedType();
1999     pinnedStringDesc.MakePinned();
2000     DWORD dwPinnedStringLocal = pslILEmit->NewLocal(pinnedStringDesc);
2001
2002     // pinnedString = managed
2003     EmitLoadManagedValue(pslILEmit);
2004     pslILEmit->EmitSTLOC(dwPinnedStringLocal);
2005
2006     // hstring = HSTRINGMarshaler.ConvertManagedToNativeReference(pinnedString, out HStringHeader)
2007     pslILEmit->EmitLDLOC(dwPinnedStringLocal);
2008     pslILEmit->EmitLDLOCA(dwHStringHeaderLocal);
2009     pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_NATIVE_REFERENCE, 2, 1);
2010
2011     if (g_pConfig->InteropLogArguments())
2012     {
2013         m_pslNDirect->EmitLogNativeArgument(pslILEmit, dwPinnedStringLocal);
2014     }
2015
2016     EmitStoreNativeValue(pslILEmit);
2017 }
2018
2019 void ILHSTRINGMarshaler::EmitConvertCLRToHSTRING(ILCodeStream* pslILEmit)
2020 {
2021     CONTRACTL
2022     {
2023         STANDARD_VM_CHECK;
2024         PRECONDITION(CheckPointer(pslILEmit));
2025     }
2026     CONTRACTL_END;
2027
2028     // hstring = HSTRINGMarshaler.ConvertManagedToNative(managed);
2029     EmitLoadManagedValue(pslILEmit);
2030     pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_NATIVE, 1, 1);
2031     EmitStoreNativeValue(pslILEmit);
2032 }
2033
2034 void ILHSTRINGMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2035 {
2036     STANDARD_VM_CONTRACT;
2037
2038     //
2039     // To convert an HSTRING to a CLR String:
2040     //      1. WindowsGetStringRawBuffer() to get the raw string data
2041     //      2. WindowsGetStringLen() to get the string length
2042     //      3. Construct a System.String from these parameters
2043     //      4. Release the HSTRING
2044     //
2045
2046     // string = HSTRINGMarshaler.ConvertNativeToManaged(native);
2047     EmitLoadNativeValue(pslILEmit);
2048     pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CONVERT_TO_MANAGED, 1, 1);
2049     EmitStoreManagedValue(pslILEmit);
2050 }
2051
2052
2053 void ILHSTRINGMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
2054 {
2055     STANDARD_VM_CONTRACT;
2056
2057     // HStringMarshaler.ClearNative(hstring)
2058     EmitLoadNativeValue(pslILEmit);
2059     pslILEmit->EmitCALL(METHOD__HSTRINGMARSHALER__CLEAR_NATIVE, 1, 0);
2060 }
2061
2062 #endif // FEATURE_COMINTEROP
2063
2064 LocalDesc ILCUTF8Marshaler::GetManagedType()
2065 {
2066         LIMITED_METHOD_CONTRACT;
2067
2068         return LocalDesc(ELEMENT_TYPE_STRING);
2069 }
2070
2071 void ILCUTF8Marshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2072 {
2073         STANDARD_VM_CONTRACT;
2074
2075         DWORD dwUtf8MarshalFlags =
2076                 (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) |
2077                 (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
2078
2079         bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags);
2080         if (bPassByValueInOnly)
2081         {
2082                 DWORD dwBufSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
2083                 m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
2084
2085                 // LocalBuffer = 0
2086                 pslILEmit->EmitLoadNullPtr();
2087                 pslILEmit->EmitSTLOC(m_dwLocalBuffer);
2088
2089                 ILCodeLabel* pNoOptimize = pslILEmit->NewCodeLabel();
2090
2091                 // if == NULL, goto NoOptimize
2092                 EmitLoadManagedValue(pslILEmit);
2093                 pslILEmit->EmitBRFALSE(pNoOptimize);
2094                                                 
2095                 // (String.Length + 1)
2096                 // Characters would be # of characters + 1 in case left over high surrogate is ?
2097                 EmitLoadManagedValue(pslILEmit);
2098                 pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
2099                 pslILEmit->EmitLDC(1);
2100                 pslILEmit->EmitADD();
2101
2102                 // Max 3 bytes per char.
2103                 // (String.Length + 1) * 3              
2104                 pslILEmit->EmitLDC(3);
2105                 pslILEmit->EmitMUL();
2106
2107                 // +1 for the 0x0 that we put in.
2108                 // ((String.Length + 1) * 3) + 1
2109                 pslILEmit->EmitLDC(1);
2110                 pslILEmit->EmitADD();
2111                                 
2112                 // BufSize = ( (String.Length+1) * 3) + 1
2113                 pslILEmit->EmitSTLOC(dwBufSize);
2114
2115                 // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
2116                 pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
2117                 pslILEmit->EmitLDLOC(dwBufSize);
2118                 pslILEmit->EmitCLT();
2119                 pslILEmit->EmitBRTRUE(pNoOptimize);
2120
2121                 // LocalBuffer = localloc(BufSize);
2122                 pslILEmit->EmitLDLOC(dwBufSize);
2123                 pslILEmit->EmitLOCALLOC();
2124                 pslILEmit->EmitSTLOC(m_dwLocalBuffer);
2125
2126                 // NoOptimize:
2127                 pslILEmit->EmitLabel(pNoOptimize);
2128         }
2129
2130         // UTF8Marshaler.ConvertToNative(dwUtf8MarshalFlags,pManaged, pLocalBuffer)
2131         pslILEmit->EmitLDC(dwUtf8MarshalFlags);
2132         EmitLoadManagedValue(pslILEmit);
2133
2134         if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
2135         {
2136                 pslILEmit->EmitLDLOC(m_dwLocalBuffer);
2137         }
2138         else
2139         {
2140                 pslILEmit->EmitLoadNullPtr();
2141         }
2142
2143         pslILEmit->EmitCALL(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE, 3, 1);
2144
2145         EmitStoreNativeValue(pslILEmit);
2146 }
2147
2148 void ILCUTF8Marshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2149 {
2150         STANDARD_VM_CONTRACT;
2151
2152         EmitLoadNativeValue(pslILEmit);
2153         pslILEmit->EmitCALL(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED, 1, 1);
2154         EmitStoreManagedValue(pslILEmit);
2155 }
2156
2157
2158 LocalDesc ILCSTRMarshaler::GetManagedType()
2159 {
2160     LIMITED_METHOD_CONTRACT;
2161     
2162     return LocalDesc(ELEMENT_TYPE_STRING);
2163 }
2164
2165 void ILCSTRMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2166 {
2167     STANDARD_VM_CONTRACT;
2168
2169     DWORD dwAnsiMarshalFlags = 
2170         (m_pargs->m_pMarshalInfo->GetBestFitMapping() & 0xFF) | 
2171         (m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar() << 8);
2172
2173     bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags);
2174     if (bPassByValueInOnly)
2175     {
2176         DWORD dwBufSize = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
2177         m_dwLocalBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I);
2178
2179         // LocalBuffer = 0
2180         pslILEmit->EmitLoadNullPtr();
2181         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
2182
2183         ILCodeLabel* pNoOptimize = pslILEmit->NewCodeLabel(); 
2184
2185         // if == NULL, goto NoOptimize
2186         EmitLoadManagedValue(pslILEmit);
2187         pslILEmit->EmitBRFALSE(pNoOptimize);
2188
2189         // String.Length + 2
2190         EmitLoadManagedValue(pslILEmit);
2191         pslILEmit->EmitCALL(METHOD__STRING__GET_LENGTH, 1, 1);
2192         pslILEmit->EmitLDC(2);
2193         pslILEmit->EmitADD();
2194
2195         // (String.Length + 2) * GetMaxDBCSCharByteSize()
2196         pslILEmit->EmitLDSFLD(pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__MARSHAL__SYSTEM_MAX_DBCS_CHAR_SIZE)));
2197         pslILEmit->EmitMUL();
2198
2199         // BufSize = (String.Length + 2) * GetMaxDBCSCharByteSize()
2200         pslILEmit->EmitSTLOC(dwBufSize);
2201
2202         // if (MAX_LOCAL_BUFFER_LENGTH < BufSize ) goto NoOptimize
2203         pslILEmit->EmitLDC(MAX_LOCAL_BUFFER_LENGTH);
2204         pslILEmit->EmitLDLOC(dwBufSize);
2205         pslILEmit->EmitCLT();
2206         pslILEmit->EmitBRTRUE(pNoOptimize);
2207
2208         // LocalBuffer = localloc(BufSize);
2209         pslILEmit->EmitLDLOC(dwBufSize);
2210         pslILEmit->EmitLOCALLOC();
2211         pslILEmit->EmitSTLOC(m_dwLocalBuffer);
2212
2213         // NoOptimize:
2214         pslILEmit->EmitLabel(pNoOptimize);
2215     }
2216
2217     // CSTRMarshaler.ConvertToNative pManaged, dwAnsiMarshalFlags, pLocalBuffer
2218     pslILEmit->EmitLDC(dwAnsiMarshalFlags);
2219     EmitLoadManagedValue(pslILEmit);
2220
2221     if (m_dwLocalBuffer != LOCAL_NUM_UNUSED)
2222     {
2223         pslILEmit->EmitLDLOC(m_dwLocalBuffer);
2224     }
2225     else
2226     {
2227         pslILEmit->EmitLoadNullPtr();
2228     }
2229
2230     pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_TO_NATIVE, 3, 1);
2231     
2232     EmitStoreNativeValue(pslILEmit);
2233 }
2234
2235 void ILCSTRMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2236 {
2237     STANDARD_VM_CONTRACT;
2238
2239     EmitLoadNativeValue(pslILEmit);
2240     pslILEmit->EmitCALL(METHOD__CSTRMARSHALER__CONVERT_TO_MANAGED, 1, 1);
2241     EmitStoreManagedValue(pslILEmit);
2242 }
2243
2244 LocalDesc ILLayoutClassPtrMarshalerBase::GetNativeType()
2245 {
2246     LIMITED_METHOD_CONTRACT;
2247     
2248     return LocalDesc(ELEMENT_TYPE_I); // ptr to struct
2249 }
2250
2251 LocalDesc ILLayoutClassPtrMarshalerBase::GetManagedType()
2252 {
2253     LIMITED_METHOD_CONTRACT;
2254     
2255     return LocalDesc(m_pargs->m_pMT);
2256 }
2257
2258 void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
2259 {
2260     STANDARD_VM_CONTRACT;
2261     
2262     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2263     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2264
2265     pslILEmit->EmitLoadNullPtr();
2266     EmitStoreNativeValue(pslILEmit);
2267     
2268     EmitLoadManagedValue(pslILEmit);
2269     pslILEmit->EmitBRFALSE(pNullRefLabel);
2270     pslILEmit->EmitLDC(uNativeSize);
2271     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
2272     pslILEmit->EmitDUP();           // for INITBLK
2273     EmitStoreNativeValue(pslILEmit);
2274
2275     // initialize local block we just allocated
2276     pslILEmit->EmitLDC(0);
2277     pslILEmit->EmitLDC(uNativeSize);
2278     pslILEmit->EmitINITBLK();
2279
2280     pslILEmit->EmitLabel(pNullRefLabel);
2281 }
2282
2283 void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceCLRToNativeTemp(ILCodeStream* pslILEmit)
2284 {
2285     STANDARD_VM_CONTRACT;
2286
2287     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2288     if (uNativeSize > s_cbStackAllocThreshold)
2289     {
2290         EmitConvertSpaceCLRToNative(pslILEmit);
2291     }
2292     else
2293     {
2294         ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2295
2296         pslILEmit->EmitLoadNullPtr();
2297         EmitStoreNativeValue(pslILEmit);
2298         
2299         EmitLoadManagedValue(pslILEmit);
2300         pslILEmit->EmitBRFALSE(pNullRefLabel);
2301
2302         pslILEmit->EmitLDC(uNativeSize);
2303         pslILEmit->EmitLOCALLOC();
2304         pslILEmit->EmitDUP();           // for INITBLK
2305         EmitStoreNativeValue(pslILEmit);
2306
2307         // initialize local block we just allocated
2308         pslILEmit->EmitLDC(0);
2309         pslILEmit->EmitLDC(uNativeSize);
2310         pslILEmit->EmitINITBLK();
2311
2312         pslILEmit->EmitLabel(pNullRefLabel);
2313     }
2314 }
2315
2316 void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
2317 {
2318     STANDARD_VM_CONTRACT;
2319     
2320     EmitConvertSpaceCLRToNativeTemp(pslILEmit);
2321     EmitConvertContentsCLRToNative(pslILEmit);
2322 }
2323
2324 void ILLayoutClassPtrMarshalerBase::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
2325 {
2326     STANDARD_VM_CONTRACT;
2327
2328     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2329
2330     EmitLoadNativeValue(pslILEmit);
2331     pslILEmit->EmitBRFALSE(pNullRefLabel);
2332
2333     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
2334     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
2335     // static object AllocateInternal(IntPtr typeHandle);
2336     pslILEmit->EmitCALL(METHOD__STUBHELPERS__ALLOCATE_INTERNAL, 1, 1);
2337     EmitStoreManagedValue(pslILEmit);
2338     pslILEmit->EmitLabel(pNullRefLabel);
2339 }
2340
2341
2342 bool ILLayoutClassPtrMarshalerBase::NeedsClearNative()
2343 {
2344     LIMITED_METHOD_CONTRACT;
2345     return true;
2346 }
2347
2348 void ILLayoutClassPtrMarshalerBase::EmitClearNative(ILCodeStream* pslILEmit)
2349 {
2350     STANDARD_VM_CONTRACT;
2351     
2352     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2353
2354     EmitLoadNativeValue(pslILEmit);
2355     pslILEmit->EmitBRFALSE(pNullRefLabel);
2356
2357     EmitClearNativeContents(pslILEmit);
2358     EmitLoadNativeValue(pslILEmit);
2359     pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
2360
2361     pslILEmit->EmitLabel(pNullRefLabel);
2362 }
2363
2364 void ILLayoutClassPtrMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
2365 {
2366     STANDARD_VM_CONTRACT;
2367
2368     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2369     if (uNativeSize > s_cbStackAllocThreshold)
2370     {
2371         EmitClearNative(pslILEmit);
2372     }
2373     else
2374     {
2375         ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2376         EmitLoadNativeValue(pslILEmit);
2377         pslILEmit->EmitBRFALSE(pNullRefLabel);
2378         
2379         EmitClearNativeContents(pslILEmit);
2380         
2381         pslILEmit->EmitLabel(pNullRefLabel);
2382     }
2383 }
2384
2385
2386
2387 void ILLayoutClassPtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2388 {
2389     STANDARD_VM_CONTRACT;
2390
2391     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2392     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2393
2394     EmitLoadNativeValue(pslILEmit);
2395     pslILEmit->EmitBRFALSE(pNullRefLabel);
2396
2397     EmitLoadNativeValue(pslILEmit);
2398     pslILEmit->EmitLDC(0);
2399     pslILEmit->EmitLDC(uNativeSize);
2400     pslILEmit->EmitINITBLK();        
2401
2402     EmitLoadManagedValue(pslILEmit);
2403     EmitLoadNativeValue(pslILEmit);
2404
2405     m_pslNDirect->LoadCleanupWorkList(pslILEmit);
2406
2407     // static void FmtClassUpdateNativeInternal(object obj, byte* pNative, IntPtr pOptionalCleanupList);
2408
2409     pslILEmit->EmitCALL(METHOD__STUBHELPERS__FMT_CLASS_UPDATE_NATIVE_INTERNAL, 3, 0);
2410     pslILEmit->EmitLabel(pNullRefLabel);
2411 }
2412
2413 void ILLayoutClassPtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2414 {
2415     STANDARD_VM_CONTRACT;
2416     
2417     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2418     
2419     EmitLoadManagedValue(pslILEmit);
2420     pslILEmit->EmitBRFALSE(pNullRefLabel);
2421
2422     EmitLoadManagedValue(pslILEmit);
2423     EmitLoadNativeValue(pslILEmit);
2424
2425     // static void FmtClassUpdateCLRInternal(object obj, byte* pNative);
2426     pslILEmit->EmitCALL(METHOD__STUBHELPERS__FMT_CLASS_UPDATE_CLR_INTERNAL, 2, 0);
2427     pslILEmit->EmitLabel(pNullRefLabel);
2428 }
2429
2430 void ILLayoutClassPtrMarshaler::EmitClearNativeContents(ILCodeStream * pslILEmit)
2431 {
2432     STANDARD_VM_CONTRACT;
2433
2434     int tokManagedType = pslILEmit->GetToken(m_pargs->m_pMT);
2435     
2436     EmitLoadNativeValue(pslILEmit);
2437     pslILEmit->EmitLDTOKEN(tokManagedType);
2438     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
2439
2440     // static void LayoutDestroyNativeInternal(byte* pNative, IntPtr pMT);
2441     pslILEmit->EmitCALL(METHOD__STUBHELPERS__LAYOUT_DESTROY_NATIVE_INTERNAL, 2, 0);
2442 }
2443
2444
2445 void ILBlittablePtrMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
2446 {
2447     STANDARD_VM_CONTRACT;
2448
2449     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2450     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2451     int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__PINNING_HELPER__M_DATA));
2452
2453     EmitLoadNativeValue(pslILEmit);
2454     pslILEmit->EmitBRFALSE(pNullRefLabel);
2455
2456     EmitLoadNativeValue(pslILEmit);                             // dest
2457
2458     EmitLoadManagedValue(pslILEmit);
2459     pslILEmit->EmitLDFLDA(fieldDef);                            // src
2460
2461     pslILEmit->EmitLDC(uNativeSize);                            // size
2462     
2463     pslILEmit->EmitCPBLK();
2464     pslILEmit->EmitLabel(pNullRefLabel);
2465 }
2466
2467 void ILBlittablePtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
2468 {
2469     STANDARD_VM_CONTRACT;
2470     
2471     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
2472     UINT uNativeSize = m_pargs->m_pMT->GetNativeSize();
2473     int fieldDef = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__PINNING_HELPER__M_DATA));
2474     
2475     EmitLoadManagedValue(pslILEmit);
2476     pslILEmit->EmitBRFALSE(pNullRefLabel);
2477
2478     EmitLoadManagedValue(pslILEmit);
2479     pslILEmit->EmitLDFLDA(fieldDef);                            // dest
2480
2481     EmitLoadNativeValue(pslILEmit);                             // src
2482
2483     pslILEmit->EmitLDC(uNativeSize);                            // size
2484
2485     pslILEmit->EmitCPBLK();
2486     pslILEmit->EmitLabel(pNullRefLabel);
2487 }
2488
2489 void ILBlittablePtrMarshaler::EmitMarshalArgumentCLRToNative()
2490 {
2491     CONTRACTL
2492     {
2493         STANDARD_VM_CHECK;
2494         PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
2495     }
2496     CONTRACTL_END;
2497
2498     EmitSetupSigAndDefaultHomesCLRToNative();
2499
2500     //
2501     // marshal
2502     //
2503
2504     ILCodeLabel* pSkipAddLabel = m_pcsMarshal->NewCodeLabel();
2505     LocalDesc managedTypePinned = GetManagedType();
2506     managedTypePinned.MakePinned();
2507     DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedTypePinned);
2508
2509     EmitLoadManagedValue(m_pcsMarshal);
2510     
2511     m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
2512     m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
2513     m_pcsMarshal->EmitCONV_U();
2514     m_pcsMarshal->EmitDUP();
2515     m_pcsMarshal->EmitBRFALSE(pSkipAddLabel);
2516     m_pcsMarshal->EmitLDC(Object::GetOffsetOfFirstField());
2517     m_pcsMarshal->EmitADD();
2518     m_pcsMarshal->EmitLabel(pSkipAddLabel);
2519
2520     if (g_pConfig->InteropLogArguments())
2521     {
2522         m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
2523     }
2524
2525     EmitStoreNativeValue(m_pcsMarshal);
2526 }
2527
2528
2529
2530
2531 MarshalerOverrideStatus ILHandleRefMarshaler::ArgumentOverride(NDirectStubLinker* psl,
2532                                                 BOOL               byref,
2533                                                 BOOL               fin,
2534                                                 BOOL               fout,
2535                                                 BOOL               fManagedToNative,
2536                                                 OverrideProcArgs*  pargs,
2537                                                 UINT*              pResID,
2538                                                 UINT               argidx,
2539                                                 UINT               nativeStackOffset)
2540 {
2541     CONTRACTL
2542     {
2543         THROWS;
2544         GC_TRIGGERS;
2545         MODE_ANY;
2546     }
2547     CONTRACTL_END;
2548
2549     ILCodeStream* pcsMarshal    = psl->GetMarshalCodeStream();
2550     ILCodeStream* pcsDispatch   = psl->GetDispatchCodeStream();
2551
2552     if (fManagedToNative && !byref)
2553     {
2554         pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I);
2555
2556
2557         // HandleRefs are valuetypes, so pinning is not needed.
2558         // The argument address is on the stack and will not move.
2559         pcsDispatch->EmitLDARGA(argidx);
2560         pcsDispatch->EmitLDC(offsetof(HANDLEREF, m_handle));
2561         pcsDispatch->EmitADD();
2562         pcsDispatch->EmitLDIND_I();
2563         return OVERRIDDEN;
2564     }
2565     else
2566     {
2567         *pResID = IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION;
2568         return DISALLOWED;
2569     }
2570 }
2571
2572 MarshalerOverrideStatus ILHandleRefMarshaler::ReturnOverride(NDirectStubLinker* psl,
2573                                               BOOL               fManagedToNative,
2574                                               BOOL               fHresultSwap,
2575                                               OverrideProcArgs*  pargs,
2576                                               UINT*              pResID)
2577 {
2578     CONTRACTL
2579     {
2580         NOTHROW;
2581         GC_NOTRIGGER;
2582         MODE_ANY;
2583     }
2584     CONTRACTL_END;
2585
2586     *pResID = IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION;
2587     return DISALLOWED;
2588 }
2589
2590 LocalDesc ILSafeHandleMarshaler::GetManagedType()
2591 {
2592     STANDARD_VM_CONTRACT;
2593
2594     return LocalDesc(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE));
2595 }
2596
2597 LocalDesc ILSafeHandleMarshaler::GetNativeType()
2598 {
2599     LIMITED_METHOD_CONTRACT;
2600
2601     return LocalDesc(ELEMENT_TYPE_I);
2602 }
2603
2604 bool ILSafeHandleMarshaler::NeedsClearNative()
2605 {
2606     LIMITED_METHOD_CONTRACT;
2607     return true;
2608 }
2609
2610 void ILSafeHandleMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
2611 {
2612     STANDARD_VM_CONTRACT;
2613
2614     _ASSERTE(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
2615
2616     // call StubHelpers::SafeHandleRelease
2617     EmitLoadManagedValue(pslILEmit);
2618     pslILEmit->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_RELEASE, 1, 0);
2619 }
2620
2621 void ILSafeHandleMarshaler::EmitMarshalArgumentCLRToNative()
2622 {
2623     CONTRACTL
2624     {
2625         STANDARD_VM_CHECK;
2626         PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
2627     }
2628     CONTRACTL_END;
2629
2630     EmitSetupSigAndDefaultHomesCLRToNative();
2631
2632     // by-value CLR-to-native SafeHandle is always passed in-only regardless of [In], [Out]
2633     // marshal and cleanup communicate via an extra local and are both emitted in this method
2634
2635     // bool <dwHandleAddRefedLocalNum> = false
2636     ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
2637     DWORD dwHandleAddRefedLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
2638     
2639     pcsSetup->EmitLDC(0);
2640     pcsSetup->EmitSTLOC(dwHandleAddRefedLocalNum);
2641
2642     // <nativeHandle> = StubHelpers::SafeHandleAddRef(<managedSH>, ref <dwHandleAddRefedLocalNum>)
2643     EmitLoadManagedValue(m_pcsMarshal);
2644     m_pcsMarshal->EmitLDLOCA(dwHandleAddRefedLocalNum);
2645     m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__SAFE_HANDLE_ADD_REF, 2, 1);
2646     EmitStoreNativeValue(m_pcsMarshal);
2647
2648     // cleanup:
2649     // if (<dwHandleAddRefedLocalNum>) StubHelpers.SafeHandleRelease(<managedSH>)
2650     ILCodeStream *pcsCleanup = m_pslNDirect->GetCleanupCodeStream();
2651     ILCodeLabel *pSkipClearNativeLabel = pcsCleanup->NewCodeLabel();
2652
2653     pcsCleanup->EmitLDLOC(dwHandleAddRefedLocalNum);
2654     pcsCleanup->EmitBRFALSE(pSkipClearNativeLabel);
2655
2656     EmitClearNativeTemp(pcsCleanup);
2657     m_pslNDirect->SetCleanupNeeded();
2658
2659     pcsCleanup->EmitLabel(pSkipClearNativeLabel);
2660 }
2661
2662 MarshalerOverrideStatus ILSafeHandleMarshaler::ArgumentOverride(NDirectStubLinker* psl,
2663                                                 BOOL               byref,
2664                                                 BOOL               fin,
2665                                                 BOOL               fout,
2666                                                 BOOL               fManagedToNative,
2667                                                 OverrideProcArgs*  pargs,
2668                                                 UINT*              pResID,
2669                                                 UINT               argidx,
2670                                                 UINT               nativeStackOffset)
2671 {
2672     CONTRACTL
2673     {
2674         THROWS;
2675         GC_TRIGGERS;
2676         MODE_ANY;
2677     }
2678     CONTRACTL_END;
2679     
2680     ILCodeStream* pslIL         = psl->GetMarshalCodeStream();
2681     ILCodeStream* pslILDispatch = psl->GetDispatchCodeStream();
2682
2683     if (fManagedToNative)
2684     {
2685         if (byref)
2686         {
2687             pslIL->SetStubTargetArgType(ELEMENT_TYPE_I);
2688
2689             // The specific SafeHandle subtype we're dealing with here.
2690             MethodTable *pHandleType = pargs->m_pMT;
2691
2692             // Out SafeHandle parameters must not be abstract.
2693             if (fout && pHandleType->IsAbstract())
2694             {
2695                 *pResID = IDS_EE_BADMARSHAL_ABSTRACTOUTSAFEHANDLE;
2696                 return DISALLOWED;
2697             }
2698
2699             // We rely on the SafeHandle having a default constructor.
2700             if (!pHandleType->HasDefaultConstructor())
2701             {
2702                 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
2703                 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
2704             }
2705
2706             // Grab the token for the native handle field embedded inside the SafeHandle. We'll be using it to direct access the
2707             // native handle later.
2708             mdToken tkNativeHandleField = pslIL->GetToken(MscorlibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE));
2709
2710             // The high level logic (note that the parameter may be in, out or both):
2711             // 1) If this is an input parameter we need to AddRef the SafeHandle and schedule a Release cleanup item.
2712             // 2) If this is an output parameter we need to preallocate a SafeHandle to wrap the new native handle value. We
2713             //    must allocate this before the native call to avoid a failure point when we already have a native resource
2714             //    allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native
2715             //    handles need to be tracked and released by a SafeHandle.
2716             // 3) Initialize a local IntPtr that will be passed to the native call. If we have an input SafeHandle the value
2717             //    comes from there otherwise we get it from the new SafeHandle (which is guaranteed to be initialized to an
2718             //    invalid handle value).
2719             // 4) If this is a out parameter we also store the original handle value (that we just computed above) in a local
2720             //    variable.
2721             // 5) After the native call, if this is an output parameter and the handle value we passed to native differs from
2722             //    the local copy we made then the new handle value is written into the output SafeHandle and that SafeHandle
2723             //    is propagated back to the caller.
2724
2725             // Locals:
2726             DWORD           dwInputHandleLocal     = 0; // The input safe handle (in only)
2727             DWORD           dwOutputHandleLocal    = 0; // The output safe handle (out only)
2728             DWORD           dwOldNativeHandleLocal = 0; // The original native handle value for comparison (out only)
2729             DWORD           dwNativeHandleLocal;    // The input (and possibly updated) native handle value
2730
2731             if (fin)
2732             {
2733                 LocalDesc locInputHandle(pHandleType);
2734                 dwInputHandleLocal = pslIL->NewLocal(locInputHandle);
2735             }
2736             if (fout)
2737             {
2738                 LocalDesc locOutputHandle(pHandleType);
2739                 dwOutputHandleLocal = pslIL->NewLocal(locOutputHandle);
2740
2741                 dwOldNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
2742             }
2743
2744             dwNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
2745
2746             // Call StubHelpers.AddToCleanupList to atomically AddRef incoming SafeHandle and schedule a cleanup work item to
2747             // perform Release after the call. The helper also returns the native handle value to us so take the opportunity
2748             // to store this in the NativeHandle local we've allocated.
2749             if (fin)
2750             {
2751                 pslIL->EmitLDARG(argidx);
2752                 pslIL->EmitLDIND_REF();
2753
2754                 pslIL->EmitSTLOC(dwInputHandleLocal);
2755
2756                 // Release the original input SafeHandle after the call.
2757                 psl->LoadCleanupWorkList(pslIL);
2758                 pslIL->EmitLDLOC(dwInputHandleLocal);
2759
2760                 // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
2761                 pslIL->EmitCALL(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST_SAFEHANDLE, 2, 1);
2762
2763                 pslIL->EmitSTLOC(dwNativeHandleLocal);
2764
2765             }
2766
2767             // For output parameters we need to allocate a new SafeHandle to hold the result.
2768             if (fout)
2769             {
2770                 MethodDesc* pMDCtor = pHandleType->GetDefaultConstructor();
2771                 pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
2772                 pslIL->EmitSTLOC(dwOutputHandleLocal);
2773
2774                 // If we didn't provide an input handle then we initialize the NativeHandle local with the (initially invalid)
2775                 // handle field set up inside the output handle by the constructor.
2776                 if (!fin)
2777                 {
2778                     pslIL->EmitLDLOC(dwOutputHandleLocal);
2779                     pslIL->EmitLDFLD(tkNativeHandleField);
2780                     pslIL->EmitSTLOC(dwNativeHandleLocal);
2781                 }
2782
2783                 // Remember the handle value we start out with so we know whether to back propagate after the native call.
2784                 pslIL->EmitLDLOC(dwNativeHandleLocal);
2785                 pslIL->EmitSTLOC(dwOldNativeHandleLocal);
2786             }
2787
2788             // Leave the address of the native handle local as the argument to the native method.
2789             pslILDispatch->EmitLDLOCA(dwNativeHandleLocal);
2790
2791             // On the output side we only backpropagate the native handle into the output SafeHandle and the output SafeHandle
2792             // to the caller if the native handle actually changed (otherwise we can end up with two SafeHandles wrapping the
2793             // same native handle, which is bad).
2794             if (fout)
2795             {
2796                 // We will use cleanup stream to avoid leaking the handle on thread abort.
2797                 psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx);
2798
2799                 psl->SetCleanupNeeded();
2800                 ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
2801
2802                 ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
2803
2804                 psl->EmitCheckForArgCleanup(pslCleanupIL,
2805                                             NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx,
2806                                             NDirectStubLinker::BranchIfNotMarshaled,
2807                                             pDoneLabel);
2808
2809                 // If this is an [in, out] handle check if the native handles have changed. If not we're finished.
2810                 if (fin)
2811                 {
2812                     pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
2813                     pslCleanupIL->EmitLDLOC(dwOldNativeHandleLocal);
2814                     pslCleanupIL->EmitCEQ();
2815                     pslCleanupIL->EmitBRTRUE(pDoneLabel);
2816                 }
2817
2818                 // Propagate the native handle into the output SafeHandle.
2819                 pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
2820                 pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
2821                 pslCleanupIL->EmitSTFLD(tkNativeHandleField);
2822
2823                 // Propagate the output SafeHandle back to the caller.
2824                 pslCleanupIL->EmitLDARG(argidx);
2825                 pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
2826                 pslCleanupIL->EmitSTIND_REF();
2827
2828                 pslCleanupIL->EmitLabel(pDoneLabel);
2829             }
2830         }
2831         else
2832         {
2833             // Avoid using the cleanup list in this common case for perf reasons (cleanup list is
2834             // unmanaged and destroying it means excessive managed<->native transitions; in addition,
2835             // as X86 IL stubs do not use interop frames, there's nothing protecting the cleanup list
2836             // and the SafeHandle references must be GC handles which does not help perf either).
2837             //
2838             // This code path generates calls to StubHelpers.SafeHandleAddRef and SafeHandleRelease.
2839             // NICE: Could SafeHandle.DangerousAddRef and DangerousRelease be implemented in managed?
2840             return HANDLEASNORMAL;
2841         }
2842
2843         return OVERRIDDEN;
2844     }
2845     else
2846     {
2847         *pResID = IDS_EE_BADMARSHAL_SAFEHANDLENATIVETOCOM;
2848         return DISALLOWED;
2849     }
2850 }
2851
2852 //---------------------------------------------------------------------------------------
2853 // 
2854 MarshalerOverrideStatus 
2855 ILSafeHandleMarshaler::ReturnOverride(
2856     NDirectStubLinker * psl, 
2857     BOOL                fManagedToNative, 
2858     BOOL                fHresultSwap, 
2859     OverrideProcArgs *  pargs, 
2860     UINT       *        pResID)
2861 {
2862     CONTRACTL
2863     {
2864         THROWS;
2865         GC_TRIGGERS;
2866         MODE_ANY;
2867         PRECONDITION(CheckPointer(psl));
2868         PRECONDITION(CheckPointer(pargs));
2869         PRECONDITION(CheckPointer(pResID));            
2870     }
2871     CONTRACTL_END;
2872
2873     ILCodeStream * pslIL         = psl->GetMarshalCodeStream();
2874     ILCodeStream * pslPostIL     = psl->GetReturnUnmarshalCodeStream();
2875     ILCodeStream * pslILDispatch = psl->GetDispatchCodeStream();
2876
2877     if (!fManagedToNative)
2878     {
2879         *pResID = IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE;
2880         return DISALLOWED;
2881     }
2882
2883     // Returned SafeHandle parameters must not be abstract.
2884     if (pargs->m_pMT->IsAbstract())
2885     {
2886         *pResID = IDS_EE_BADMARSHAL_ABSTRACTRETSAFEHANDLE;
2887         return DISALLOWED;
2888     }
2889
2890     // 1) create local for new safehandle
2891     // 2) prealloc a safehandle
2892     // 3) create local to hold returned handle
2893     // 4) [byref] add byref IntPtr to native sig
2894     // 5) [byref] pass address of local as last arg
2895     // 6) store return value in safehandle
2896
2897     // 1) create local for new safehandle        
2898     MethodTable * pMT    = pargs->m_pMT;
2899     LocalDesc     locDescReturnHandle(pMT);
2900     DWORD         dwReturnHandleLocal;
2901     
2902     dwReturnHandleLocal = pslIL->NewLocal(locDescReturnHandle);
2903     
2904     if (!pMT->HasDefaultConstructor())
2905     {
2906         MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
2907         COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
2908     }
2909
2910     // 2) prealloc a safehandle
2911     MethodDesc* pMDCtor = pMT->GetDefaultConstructor();
2912     pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
2913     pslIL->EmitSTLOC(dwReturnHandleLocal);
2914
2915     mdToken tkNativeHandleField = pslPostIL->GetToken(MscorlibBinder::GetField(FIELD__SAFE_HANDLE__HANDLE));
2916
2917     // 3) create local to hold returned handle
2918     DWORD dwReturnNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
2919
2920     if (fHresultSwap)
2921     {
2922         // initialize the native handle
2923         pslIL->EmitLDLOC(dwReturnHandleLocal);
2924         pslIL->EmitLDFLD(tkNativeHandleField);
2925         pslIL->EmitSTLOC(dwReturnNativeHandleLocal);
2926
2927         pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I4);    // native method returns an HRESULT
2928         
2929         // 4) [byref] add byref IntPtr to native sig
2930         locDescReturnHandle.ElementType[0]  = ELEMENT_TYPE_BYREF;
2931         locDescReturnHandle.ElementType[1]  = ELEMENT_TYPE_I;
2932         locDescReturnHandle.cbType          = 2;
2933         pslIL->SetStubTargetArgType(&locDescReturnHandle, false);   // extra arg is a byref IntPtr
2934
2935         // 5) [byref] pass address of local as last arg
2936         pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal);
2937
2938         // We will use cleanup stream to avoid leaking the handle on thread abort.
2939         psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
2940
2941         psl->SetCleanupNeeded();
2942         ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
2943         ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
2944
2945         psl->EmitCheckForArgCleanup(pslCleanupIL,
2946                                     NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
2947                                     NDirectStubLinker::BranchIfNotMarshaled,
2948                                     pDoneLabel);
2949
2950         // 6) store return value in safehandle
2951         pslCleanupIL->EmitLDLOC(dwReturnHandleLocal);
2952         pslCleanupIL->EmitLDLOC(dwReturnNativeHandleLocal);
2953         pslCleanupIL->EmitSTFLD(tkNativeHandleField);
2954         pslCleanupIL->EmitLabel(pDoneLabel);
2955
2956         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
2957     }
2958     else
2959     {
2960         pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I);
2961         pslPostIL->EmitSTLOC(dwReturnNativeHandleLocal);
2962
2963         // 6) store return value in safehandle
2964         // The thread abort logic knows that it must not interrupt the stub so we will
2965         // always be able to execute this sequence after returning from the call.
2966         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
2967         pslPostIL->EmitLDLOC(dwReturnNativeHandleLocal);
2968         pslPostIL->EmitSTFLD(tkNativeHandleField);
2969         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
2970     }
2971
2972     return OVERRIDDEN;
2973 } // ILSafeHandleMarshaler::ReturnOverride
2974
2975
2976 //---------------------------------------------------------------------------------------
2977 // 
2978 MarshalerOverrideStatus ILCriticalHandleMarshaler::ArgumentOverride(NDirectStubLinker* psl,
2979                                                 BOOL               byref,
2980                                                 BOOL               fin,
2981                                                 BOOL               fout,
2982                                                 BOOL               fManagedToNative,
2983                                                 OverrideProcArgs*  pargs,
2984                                                 UINT*              pResID,
2985                                                 UINT               argidx,
2986                                                 UINT               nativeStackOffset)
2987 {
2988     CONTRACTL
2989     {
2990         THROWS;
2991         GC_TRIGGERS;
2992         MODE_ANY;
2993     }
2994     CONTRACTL_END;
2995     
2996     ILCodeStream* pslIL         = psl->GetMarshalCodeStream();
2997     ILCodeStream* pslPostIL     = psl->GetUnmarshalCodeStream();
2998     ILCodeStream* pslILDispatch = psl->GetDispatchCodeStream();
2999
3000     if (fManagedToNative)
3001     {
3002         pslIL->SetStubTargetArgType(ELEMENT_TYPE_I);
3003
3004         // Grab the token for the native handle field embedded inside the CriticalHandle. We'll be using it to direct access
3005         // the native handle later.
3006         mdToken tkNativeHandleField = pslIL->GetToken(MscorlibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE));
3007
3008         if (byref)
3009         {
3010             // The specific CriticalHandle subtype we're dealing with here.
3011             MethodTable *pHandleType = pargs->m_pMT;
3012
3013             // Out CriticalHandle parameters must not be abstract.
3014             if (fout && pHandleType->IsAbstract())
3015             {
3016                 *pResID = IDS_EE_BADMARSHAL_ABSTRACTOUTCRITICALHANDLE;
3017                 return DISALLOWED;
3018             }
3019
3020             // We rely on the CriticalHandle having a default constructor.
3021             if (!pHandleType->HasDefaultConstructor())
3022             {
3023                 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
3024                 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
3025             }
3026
3027             // The high level logic (note that the parameter may be in, out or both):
3028             // 1) If this is an output parameter we need to preallocate a CriticalHandle to wrap the new native handle value. We
3029             //    must allocate this before the native call to avoid a failure point when we already have a native resource
3030             //    allocated. We must allocate a new CriticalHandle even if we have one on input since both input and output native
3031             //    handles need to be tracked and released by a CriticalHandle.
3032             // 2) Initialize a local IntPtr that will be passed to the native call. If we have an input CriticalHandle the value
3033             //    comes from there otherwise we get it from the new CriticalHandle (which is guaranteed to be initialized to an
3034             //    invalid handle value).
3035             // 3) If this is a out parameter we also store the original handle value (that we just computed above) in a local
3036             //    variable.
3037             // 4) After the native call, if this is an output parameter and the handle value we passed to native differs from
3038             //    the local copy we made then the new handle value is written into the output CriticalHandle and that
3039             //    CriticalHandle is propagated back to the caller.
3040
3041             // Locals:
3042             LocalDesc       locOutputHandle;
3043             DWORD           dwOutputHandleLocal    = 0; // The output critical handle (out only)
3044             DWORD           dwOldNativeHandleLocal = 0; // The original native handle value for comparison (out only)
3045             DWORD           dwNativeHandleLocal;    // The input (and possibly updated) native handle value
3046
3047             if (fout)
3048             {
3049                 locOutputHandle.ElementType[0]  = ELEMENT_TYPE_INTERNAL;
3050                 locOutputHandle.cbType          = 1;
3051                 locOutputHandle.InternalToken   = pHandleType;
3052
3053                 dwOutputHandleLocal = pslIL->NewLocal(locOutputHandle);
3054
3055                 dwOldNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
3056             }
3057
3058             dwNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
3059
3060
3061             // If we have an input CriticalHandle then initialize our NativeHandle local with it.
3062             if (fin)
3063             {
3064                 pslIL->EmitLDARG(argidx);
3065                 pslIL->EmitLDIND_REF();
3066                 pslIL->EmitLDFLD(tkNativeHandleField);
3067                 pslIL->EmitSTLOC(dwNativeHandleLocal);
3068             }
3069
3070             // For output parameters we need to allocate a new CriticalHandle to hold the result.
3071             if (fout)
3072             {
3073                 MethodDesc* pMDCtor = pHandleType->GetDefaultConstructor();
3074                 pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
3075                 pslIL->EmitSTLOC(dwOutputHandleLocal);
3076
3077                 // If we didn't provide an input handle then we initialize the NativeHandle local with the (initially invalid)
3078                 // handle field set up inside the output handle by the constructor.
3079                 if (!fin)
3080                 {
3081                     pslIL->EmitLDLOC(dwOutputHandleLocal);
3082                     pslIL->EmitLDFLD(tkNativeHandleField);
3083                     pslIL->EmitSTLOC(dwNativeHandleLocal);
3084                 }
3085
3086                 // Remember the handle value we start out with so we know whether to back propagate after the native call.
3087                 pslIL->EmitLDLOC(dwNativeHandleLocal);
3088                 pslIL->EmitSTLOC(dwOldNativeHandleLocal);
3089             }
3090
3091             // Leave the address of the native handle local as the argument to the native method.
3092             pslILDispatch->EmitLDLOCA(dwNativeHandleLocal);
3093
3094             if (fin)
3095             {
3096                 // prevent the CriticalHandle from being finalized during the call-out to native
3097                 pslPostIL->EmitLDARG(argidx);
3098                 pslPostIL->EmitLDIND_REF();
3099                 pslPostIL->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
3100             }
3101
3102             // On the output side we only backpropagate the native handle into the output CriticalHandle and the output
3103             // CriticalHandle to the caller if the native handle actually changed (otherwise we can end up with two
3104             // CriticalHandles wrapping the same native handle, which is bad).
3105             if (fout)
3106             {
3107                 // We will use cleanup stream to avoid leaking the handle on thread abort.
3108                 psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx);
3109
3110                 psl->SetCleanupNeeded();
3111                 ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
3112
3113                 ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
3114
3115                 psl->EmitCheckForArgCleanup(pslCleanupIL,
3116                                             NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + argidx,
3117                                             NDirectStubLinker::BranchIfNotMarshaled,
3118                                             pDoneLabel);
3119
3120                 // If this is an [in, out] handle check if the native handles have changed. If not we're finished.
3121                 if (fin)
3122                 {
3123                     pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
3124                     pslCleanupIL->EmitLDLOC(dwOldNativeHandleLocal);
3125                     pslCleanupIL->EmitCEQ();
3126                     pslCleanupIL->EmitBRTRUE(pDoneLabel);
3127                 }
3128
3129                 // Propagate the native handle into the output CriticalHandle.
3130                 pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
3131                 pslCleanupIL->EmitLDLOC(dwNativeHandleLocal);
3132                 pslCleanupIL->EmitSTFLD(tkNativeHandleField);
3133
3134                 // Propagate the output CriticalHandle back to the caller.
3135                 pslCleanupIL->EmitLDARG(argidx);
3136                 pslCleanupIL->EmitLDLOC(dwOutputHandleLocal);
3137                 pslCleanupIL->EmitSTIND_REF();
3138
3139                 pslCleanupIL->EmitLabel(pDoneLabel);
3140             }
3141         }
3142         else
3143         {
3144             pslILDispatch->EmitLDARG(argidx);
3145             pslILDispatch->EmitLDFLD(tkNativeHandleField);
3146
3147             // prevent the CriticalHandle from being finalized during the call-out to native
3148             pslPostIL->EmitLDARG(argidx);
3149             pslPostIL->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
3150         }
3151
3152         return OVERRIDDEN;
3153     }
3154     else
3155     {
3156         *pResID = IDS_EE_BADMARSHAL_CRITICALHANDLENATIVETOCOM;
3157         return DISALLOWED;
3158     }
3159 }
3160
3161 //---------------------------------------------------------------------------------------
3162 // 
3163 MarshalerOverrideStatus 
3164 ILCriticalHandleMarshaler::ReturnOverride(
3165     NDirectStubLinker * psl, 
3166     BOOL                fManagedToNative, 
3167     BOOL                fHresultSwap, 
3168     OverrideProcArgs *  pargs, 
3169     UINT       *        pResID)
3170 {
3171     CONTRACTL
3172     {
3173         THROWS;
3174         GC_TRIGGERS;
3175         MODE_ANY;
3176         PRECONDITION(CheckPointer(psl));
3177         PRECONDITION(CheckPointer(pargs));
3178         PRECONDITION(CheckPointer(pResID));            
3179     }
3180     CONTRACTL_END;
3181
3182     if (!fManagedToNative)
3183     {
3184         *pResID = IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE;
3185         return DISALLOWED;
3186     }
3187
3188     // Returned CriticalHandle parameters must not be abstract.
3189     if (pargs->m_pMT->IsAbstract())
3190     {
3191         *pResID = IDS_EE_BADMARSHAL_ABSTRACTRETCRITICALHANDLE;
3192         return DISALLOWED;
3193     }
3194
3195     ILCodeStream * pslIL         = psl->GetMarshalCodeStream();
3196     ILCodeStream * pslPostIL     = psl->GetReturnUnmarshalCodeStream();
3197     ILCodeStream * pslILDispatch = psl->GetDispatchCodeStream();
3198
3199     // 1) create local for new criticalhandle
3200     // 2) prealloc a criticalhandle
3201     // 3) create local to hold returned handle
3202     // 4) [byref] add byref IntPtr to native sig
3203     // 5) [byref] pass address of local as last arg
3204     // 6) store return value in criticalhandle
3205
3206     // 1) create local for new criticalhandle        
3207     MethodTable * pMT = pargs->m_pMT;
3208     LocalDesc     locDescReturnHandle(pMT);
3209     DWORD         dwReturnHandleLocal;
3210     
3211     dwReturnHandleLocal = pslIL->NewLocal(locDescReturnHandle);
3212     
3213     if (!pMT->HasDefaultConstructor())
3214     {
3215         MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
3216         COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
3217     }
3218
3219     // 2) prealloc a criticalhandle
3220     MethodDesc * pMDCtor = pMT->GetDefaultConstructor();
3221     pslIL->EmitNEWOBJ(pslIL->GetToken(pMDCtor), 0);
3222     pslIL->EmitSTLOC(dwReturnHandleLocal);
3223
3224     mdToken tkNativeHandleField = pslPostIL->GetToken(MscorlibBinder::GetField(FIELD__CRITICAL_HANDLE__HANDLE));
3225
3226     // 3) create local to hold returned handle
3227     DWORD dwReturnNativeHandleLocal = pslIL->NewLocal(ELEMENT_TYPE_I);
3228
3229     if (fHresultSwap)
3230     {
3231         // initialize the native handle
3232         pslIL->EmitLDLOC(dwReturnHandleLocal);
3233         pslIL->EmitLDFLD(tkNativeHandleField);
3234         pslIL->EmitSTLOC(dwReturnNativeHandleLocal);
3235
3236         pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I4);    // native method returns an HRESULT
3237         
3238         // 4) [byref] add byref IntPtr to native sig
3239         locDescReturnHandle.ElementType[0]  = ELEMENT_TYPE_BYREF;
3240         locDescReturnHandle.ElementType[1]  = ELEMENT_TYPE_I;
3241         locDescReturnHandle.cbType          = 2;
3242         pslIL->SetStubTargetArgType(&locDescReturnHandle, false);   // extra arg is a byref IntPtr
3243
3244         // 5) [byref] pass address of local as last arg
3245         pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal);
3246
3247         // We will use cleanup stream to avoid leaking the handle on thread abort.
3248         psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
3249
3250         psl->SetCleanupNeeded();
3251         ILCodeStream *pslCleanupIL = psl->GetCleanupCodeStream();
3252         ILCodeLabel *pDoneLabel = pslCleanupIL->NewCodeLabel();
3253
3254         // 6) store return value in criticalhandle
3255         psl->EmitCheckForArgCleanup(pslCleanupIL,
3256                                     NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
3257                                     NDirectStubLinker::BranchIfNotMarshaled,
3258                                     pDoneLabel);
3259
3260         pslCleanupIL->EmitLDLOC(dwReturnHandleLocal);
3261         pslCleanupIL->EmitLDLOC(dwReturnNativeHandleLocal);
3262         pslCleanupIL->EmitSTFLD(tkNativeHandleField);
3263         pslCleanupIL->EmitLabel(pDoneLabel);
3264
3265         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
3266     }
3267     else
3268     {
3269         pslIL->SetStubTargetReturnType(ELEMENT_TYPE_I);
3270         pslPostIL->EmitSTLOC(dwReturnNativeHandleLocal);
3271
3272         // 6) store return value in criticalhandle
3273         // The thread abort logic knows that it must not interrupt the stub so we will
3274         // always be able to execute this sequence after returning from the call.
3275         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
3276         pslPostIL->EmitLDLOC(dwReturnNativeHandleLocal);
3277         pslPostIL->EmitSTFLD(tkNativeHandleField);
3278         pslPostIL->EmitLDLOC(dwReturnHandleLocal);
3279     }
3280
3281     return OVERRIDDEN;
3282 } // ILCriticalHandleMarshaler::ReturnOverride
3283
3284
3285 LocalDesc ILArgIteratorMarshaler::GetNativeType()
3286 {
3287     LIMITED_METHOD_CONTRACT;
3288     
3289     return LocalDesc(ELEMENT_TYPE_I); // va_list
3290 }
3291
3292 LocalDesc ILArgIteratorMarshaler::GetManagedType()
3293 {
3294     STANDARD_VM_CONTRACT;
3295     
3296     return LocalDesc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
3297 }
3298
3299 bool ILArgIteratorMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
3300 {
3301     LIMITED_METHOD_CONTRACT;
3302     
3303     if (IsByref(dwMarshalFlags))
3304     {
3305         *pErrorResID = IDS_EE_BADMARSHAL_ARGITERATORRESTRICTION;
3306         return false;
3307     }
3308
3309     return true;
3310 }
3311
3312 void ILArgIteratorMarshaler::EmitMarshalArgumentCLRToNative()
3313 {
3314     CONTRACTL
3315     {
3316         STANDARD_VM_CHECK;
3317         PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
3318     }
3319     CONTRACTL_END;
3320
3321     EmitSetupSigAndDefaultHomesCLRToNative();
3322     
3323     //
3324     // marshal
3325     //
3326
3327     // Allocate enough memory for va_list
3328     DWORD dwVaListSizeLocal = m_pcsMarshal->NewLocal(LocalDesc(ELEMENT_TYPE_U4));
3329     EmitLoadManagedHomeAddr(m_pcsMarshal);
3330     m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__CALC_VA_LIST_SIZE, 1, 1);
3331     m_pcsMarshal->EmitSTLOC(dwVaListSizeLocal);    
3332     m_pcsMarshal->EmitLDLOC(dwVaListSizeLocal);
3333     m_pcsMarshal->EmitLOCALLOC();
3334     EmitStoreNativeValue(m_pcsMarshal);
3335     
3336     // void MarshalToUnmanagedVaListInternal(cbVaListSize, va_list, VARARGS* data)
3337     EmitLoadNativeValue(m_pcsMarshal);
3338     m_pcsMarshal->EmitLDLOC(dwVaListSizeLocal);
3339     EmitLoadManagedHomeAddr(m_pcsMarshal);
3340     m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__MARSHAL_TO_UNMANAGED_VA_LIST_INTERNAL, 3, 0);
3341 }
3342
3343 void ILArgIteratorMarshaler::EmitMarshalArgumentNativeToCLR()
3344 {
3345     CONTRACTL
3346     {
3347         STANDARD_VM_CHECK;
3348         PRECONDITION(!IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
3349     }
3350     CONTRACTL_END;
3351
3352     EmitSetupSigAndDefaultHomesNativeToCLR();
3353     
3354     EmitLoadNativeValue(m_pcsMarshal);
3355     EmitLoadManagedHomeAddr(m_pcsMarshal);
3356
3357     // void MarshalToManagedVaList(va_list va, VARARGS *dataout)
3358     m_pcsMarshal->EmitCALL(METHOD__STUBHELPERS__MARSHAL_TO_MANAGED_VA_LIST_INTERNAL, 2, 0);    
3359 }
3360
3361
3362 LocalDesc ILArrayWithOffsetMarshaler::GetNativeType()
3363 {
3364     LIMITED_METHOD_CONTRACT;
3365     
3366     return LocalDesc(ELEMENT_TYPE_I);
3367 }
3368
3369 LocalDesc ILArrayWithOffsetMarshaler::GetManagedType()
3370 {
3371     STANDARD_VM_CONTRACT;
3372     
3373     return LocalDesc(MscorlibBinder::GetClass(CLASS__ARRAY_WITH_OFFSET));
3374 }
3375
3376 bool ILArrayWithOffsetMarshaler::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
3377 {
3378     LIMITED_METHOD_CONTRACT;
3379     
3380     if (IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags) && IsIn(dwMarshalFlags) && IsOut(dwMarshalFlags))
3381     {
3382         return true;
3383     }    
3384
3385     *pErrorResID = IDS_EE_BADMARSHAL_AWORESTRICTION;
3386
3387     return false;
3388 }
3389
3390 void ILArrayWithOffsetMarshaler::EmitConvertSpaceAndContentsCLRToNativeTemp(ILCodeStream* pslILEmit)
3391 {
3392     CONTRACTL
3393     {
3394         STANDARD_VM_CHECK;
3395
3396         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwCountLocalNum);
3397         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwOffsetLocalNum);
3398         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwPinnedLocalNum);
3399     }
3400     CONTRACTL_END;
3401     
3402     int tokArrayWithOffset_m_array = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_ARRAY));
3403     int tokArrayWithOffset_m_count = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_COUNT));
3404     
3405     ILCodeLabel* pNonNullLabel = pslILEmit->NewCodeLabel();
3406     ILCodeLabel* pSlowAllocPathLabel = pslILEmit->NewCodeLabel();
3407     ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
3408
3409     m_dwCountLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
3410
3411     //
3412     // Convert the space
3413     //
3414
3415     EmitLoadManagedValue(pslILEmit);
3416     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
3417     pslILEmit->EmitBRTRUE(pNonNullLabel);
3418
3419     pslILEmit->EmitLoadNullPtr();
3420     pslILEmit->EmitBR(pDoneLabel);
3421     pslILEmit->EmitLabel(pNonNullLabel);
3422
3423     EmitLoadManagedValue(pslILEmit);
3424     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_count);
3425     pslILEmit->EmitDUP();
3426     pslILEmit->EmitSTLOC(m_dwCountLocalNum);
3427     pslILEmit->EmitDUP();
3428     pslILEmit->EmitLDC(s_cbStackAllocThreshold);
3429     pslILEmit->EmitCGT_UN();
3430     pslILEmit->EmitBRTRUE(pSlowAllocPathLabel);
3431
3432     // localloc
3433     pslILEmit->EmitLOCALLOC();
3434
3435     pslILEmit->EmitBR(pDoneLabel);
3436     pslILEmit->EmitLabel(pSlowAllocPathLabel);
3437
3438     // AllocCoTaskMem
3439     pslILEmit->EmitCALL(METHOD__MARSHAL__ALLOC_CO_TASK_MEM, 1, 1);
3440
3441     pslILEmit->EmitLabel(pDoneLabel);
3442     EmitStoreNativeValue(pslILEmit);
3443
3444     //
3445     // Convert the contents
3446     //
3447
3448     int tokArrayWithOffset_m_offset = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_OFFSET));
3449
3450     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
3451
3452     LocalDesc locDescPinned;
3453     locDescPinned.cbType = 2;
3454     locDescPinned.ElementType[0] = ELEMENT_TYPE_PINNED;
3455     locDescPinned.ElementType[1] = ELEMENT_TYPE_OBJECT;
3456     m_dwPinnedLocalNum = pslILEmit->NewLocal(locDescPinned);
3457     m_dwOffsetLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
3458
3459     EmitLoadManagedValue(pslILEmit);
3460     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
3461     pslILEmit->EmitBRFALSE(pNullRefLabel);
3462
3463     EmitLoadManagedValue(pslILEmit);
3464     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
3465     pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
3466
3467     EmitLoadNativeValue(pslILEmit);                 // dest
3468
3469     pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
3470     pslILEmit->EmitCONV_I();
3471     pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
3472     pslILEmit->EmitCALL(METHOD__ARRAY__GET_DATA_PTR_OFFSET_INTERNAL, 1, 1);
3473     pslILEmit->EmitADD(); // TODO Phase5: Use UnsafeAddrOfPinnedArrayElement
3474
3475     EmitLoadManagedValue(pslILEmit);
3476     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_offset);
3477     pslILEmit->EmitDUP();
3478     pslILEmit->EmitSTLOC(m_dwOffsetLocalNum);
3479     pslILEmit->EmitADD();                           // src
3480     pslILEmit->EmitLDLOC(m_dwCountLocalNum);        // len
3481
3482     // static void Memcpy(byte* dest, byte* src, int len)
3483     pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY, 3, 0);
3484
3485     pslILEmit->EmitLDNULL();
3486     pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
3487
3488     pslILEmit->EmitLabel(pNullRefLabel);
3489 }
3490
3491 void ILArrayWithOffsetMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
3492 {
3493     CONTRACTL
3494     {
3495         STANDARD_VM_CHECK;
3496
3497         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwCountLocalNum);
3498         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwOffsetLocalNum);
3499         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED != m_dwPinnedLocalNum);
3500     }
3501     CONTRACTL_END;
3502
3503     int tokArrayWithOffset_m_array = pslILEmit->GetToken(MscorlibBinder::GetField(FIELD__ARRAY_WITH_OFFSET__M_ARRAY));
3504
3505     ILCodeLabel* pNullRefLabel = pslILEmit->NewCodeLabel();
3506
3507     EmitLoadManagedValue(pslILEmit);
3508     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
3509     pslILEmit->EmitBRFALSE(pNullRefLabel);
3510     
3511     EmitLoadManagedValue(pslILEmit);
3512     pslILEmit->EmitLDFLD(tokArrayWithOffset_m_array);
3513     pslILEmit->EmitSTLOC(m_dwPinnedLocalNum);
3514
3515     pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
3516     pslILEmit->EmitCONV_I();
3517     pslILEmit->EmitLDLOC(m_dwPinnedLocalNum);
3518     pslILEmit->EmitCALL(METHOD__ARRAY__GET_DATA_PTR_OFFSET_INTERNAL, 1, 1);
3519     pslILEmit->EmitADD(); // TODO Phase5: Use UnsafeAddrOfPinnedArrayElement
3520
3521     pslILEmit->EmitLDLOC(m_dwOffsetLocalNum);
3522     pslILEmit->EmitADD();                           // dest
3523
3524     EmitLoadNativeValue(pslILEmit);                 // src
3525
3526     pslILEmit->EmitLDLOC(m_dwCountLocalNum);        // len
3527
3528     // static void Memcpy(byte* dest, byte* src, int len)
3529     pslILEmit->EmitCALL(METHOD__BUFFER__MEMCPY, 3, 0);
3530
3531     pslILEmit->EmitLDNULL();
3532     pslILEmit->EmitSTLOC(m_dwPinnedLocalNum); 
3533
3534     pslILEmit->EmitLabel(pNullRefLabel);
3535 }
3536
3537 void ILArrayWithOffsetMarshaler::EmitClearNativeTemp(ILCodeStream* pslILEmit)
3538 {
3539     STANDARD_VM_CONTRACT;
3540
3541     ILCodeLabel* pDoneLabel = pslILEmit->NewCodeLabel();
3542     
3543     pslILEmit->EmitLDLOC(m_dwCountLocalNum);
3544     pslILEmit->EmitLDC(s_cbStackAllocThreshold);
3545     pslILEmit->EmitCGT_UN();
3546     pslILEmit->EmitBRFALSE(pDoneLabel);
3547
3548     // CoTaskMemFree
3549     EmitLoadNativeValue(pslILEmit);
3550     pslILEmit->EmitCALL(METHOD__WIN32NATIVE__COTASKMEMFREE, 1, 0);
3551
3552     pslILEmit->EmitLabel(pDoneLabel);
3553 }
3554
3555 LocalDesc ILAsAnyMarshalerBase::GetNativeType()
3556 {
3557     LIMITED_METHOD_CONTRACT;
3558     
3559     return LocalDesc(ELEMENT_TYPE_I);
3560 }
3561
3562 LocalDesc ILAsAnyMarshalerBase::GetManagedType()
3563 {
3564     LIMITED_METHOD_CONTRACT;
3565     
3566     return LocalDesc(ELEMENT_TYPE_OBJECT);
3567 }
3568
3569 bool ILAsAnyMarshalerBase::SupportsArgumentMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
3570 {
3571     WRAPPER_NO_CONTRACT;
3572     
3573     if (IsCLRToNative(dwMarshalFlags) && !IsByref(dwMarshalFlags))
3574     {
3575         return true;
3576     }
3577
3578     *pErrorResID = IDS_EE_BADMARSHAL_ASANYRESTRICTION;
3579     return false;
3580 }
3581
3582 bool ILAsAnyMarshalerBase::SupportsReturnMarshal(DWORD dwMarshalFlags, UINT* pErrorResID)
3583 {
3584     LIMITED_METHOD_CONTRACT;
3585     *pErrorResID = IDS_EE_BADMARSHAL_ASANYRESTRICTION;
3586     return false;
3587 }
3588
3589 void ILAsAnyMarshalerBase::EmitMarshalArgumentCLRToNative()
3590 {
3591     CONTRACTL
3592     {
3593         STANDARD_VM_CHECK;
3594         PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
3595         CONSISTENCY_CHECK(LOCAL_NUM_UNUSED == m_dwMarshalerLocalNum);
3596     }
3597     CONTRACTL_END;
3598
3599     EmitSetupSigAndDefaultHomesCLRToNative();
3600
3601     BYTE inout      = (IsIn(m_dwMarshalFlags) ? ML_IN : 0) | (IsOut(m_dwMarshalFlags) ? ML_OUT : 0);
3602     BYTE fIsAnsi    = IsAnsi() ? 1 : 0;
3603     BYTE fBestFit   = m_pargs->m_pMarshalInfo->GetBestFitMapping();
3604     BYTE fThrow     = m_pargs->m_pMarshalInfo->GetThrowOnUnmappableChar();
3605
3606     DWORD dwFlags = 0;
3607     
3608     dwFlags |= inout    << 24;
3609     dwFlags |= fIsAnsi  << 16;
3610     dwFlags |= fThrow   <<  8;
3611     dwFlags |= fBestFit <<  0;
3612
3613     //
3614     // marshal
3615     //
3616
3617     LocalDesc marshalerType(MscorlibBinder::GetClass(CLASS__ASANY_MARSHALER));
3618     m_dwMarshalerLocalNum = m_pcsMarshal->NewLocal(marshalerType);
3619     DWORD dwTmpLocalNum = m_pcsMarshal->NewLocal(ELEMENT_TYPE_I);
3620
3621     m_pcsMarshal->EmitLDC(sizeof(MngdNativeArrayMarshaler));
3622     m_pcsMarshal->EmitLOCALLOC();
3623     m_pcsMarshal->EmitSTLOC(dwTmpLocalNum);
3624
3625     // marshaler = new AsAnyMarshaler(local_buffer)
3626     m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
3627     m_pcsMarshal->EmitINITOBJ(m_pcsMarshal->GetToken(marshalerType.InternalToken));
3628
3629     m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
3630     m_pcsMarshal->EmitLDLOC(dwTmpLocalNum);
3631     m_pcsMarshal->EmitCALL(METHOD__ASANY_MARSHALER__CTOR, 2, 0);
3632
3633     // nativeValue = marshaler.ConvertToNative(managedValue, flags);
3634     m_pcsMarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
3635     EmitLoadManagedValue(m_pcsMarshal);
3636     m_pcsMarshal->EmitLDC(dwFlags);
3637     m_pcsMarshal->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_NATIVE, 3, 1);
3638     EmitStoreNativeValue(m_pcsMarshal);
3639
3640     //
3641     // unmarshal
3642     //
3643     if (IsOut(m_dwMarshalFlags))
3644     {
3645         // marshaler.ConvertToManaged(managedValue, nativeValue)
3646         m_pcsUnmarshal->EmitLDLOCA(m_dwMarshalerLocalNum);
3647         EmitLoadManagedValue(m_pcsUnmarshal);
3648         EmitLoadNativeValue(m_pcsUnmarshal);
3649         m_pcsUnmarshal->EmitCALL(METHOD__ASANY_MARSHALER__CONVERT_TO_MANAGED, 3, 0);
3650     }
3651
3652     //
3653     // cleanup
3654     //
3655     EmitCleanupCLRToNativeTemp();
3656 }
3657
3658 bool ILAsAnyMarshalerBase::NeedsClearNative()
3659 {
3660     LIMITED_METHOD_CONTRACT;
3661     return true;
3662 }
3663
3664 void ILAsAnyMarshalerBase::EmitClearNativeTemp(ILCodeStream* pslILEmit)
3665 {
3666     STANDARD_VM_CONTRACT;
3667
3668     // marshaler.ClearNative(nativeHome)
3669     pslILEmit->EmitLDLOCA(m_dwMarshalerLocalNum);
3670     EmitLoadNativeValue(pslILEmit);
3671     pslILEmit->EmitCALL(METHOD__ASANY_MARSHALER__CLEAR_NATIVE, 2, 0);
3672 }
3673
3674 // we can get away with putting the GetManagedType and GetNativeType on ILMngdMarshaler because
3675 // currently it is only used for reference marshaling where this is appropriate.  If it became
3676 // used for something else, we would want to move this down in the inheritence tree..
3677 LocalDesc ILMngdMarshaler::GetNativeType()
3678 {
3679     LIMITED_METHOD_CONTRACT;
3680     
3681     return LocalDesc(ELEMENT_TYPE_I);
3682 }
3683
3684 LocalDesc ILMngdMarshaler::GetManagedType()
3685 {
3686     LIMITED_METHOD_CONTRACT;
3687     
3688     return LocalDesc(ELEMENT_TYPE_OBJECT);
3689 }
3690
3691 void ILMngdMarshaler::EmitCallMngdMarshalerMethod(ILCodeStream* pslILEmit, MethodDesc *pMD)
3692 {
3693     STANDARD_VM_CONTRACT;
3694
3695     if (pMD != NULL)
3696     {
3697         MetaSig sig(pMD);
3698         UINT numArgs = sig.NumFixedArgs();
3699
3700         if (numArgs == 3)
3701         {
3702             EmitLoadMngdMarshaler(pslILEmit);
3703         }
3704         else
3705         {
3706             _ASSERTE(numArgs == 2);
3707         }
3708
3709         EmitLoadManagedHomeAddr(pslILEmit);
3710         EmitLoadNativeHomeAddr(pslILEmit);
3711
3712         pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), numArgs, 0);
3713     }
3714 }
3715
3716 bool ILNativeArrayMarshaler::UsePinnedArraySpecialCase()
3717 {
3718     if (IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && (NULL == OleVariant::GetMarshalerForVarType(m_pargs->na.m_vt, TRUE)))
3719     {
3720         return true;
3721     }
3722
3723     return false;
3724 }
3725
3726 void ILNativeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
3727 {
3728     STANDARD_VM_CONTRACT;
3729
3730     if (UsePinnedArraySpecialCase())
3731     {
3732         return;
3733     }
3734             
3735     m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
3736         
3737     pslILEmit->EmitLDC(sizeof(MngdNativeArrayMarshaler));
3738     pslILEmit->EmitLOCALLOC();
3739     pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
3740
3741     CREATE_MARSHALER_CARRAY_OPERANDS mops;
3742     m_pargs->m_pMarshalInfo->GetMops(&mops);
3743
3744     pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
3745
3746     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(mops.methodTable));
3747     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
3748
3749     DWORD dwFlags = mops.elementType;
3750     dwFlags |= (((DWORD)mops.bestfitmapping)        << 16);
3751     dwFlags |= (((DWORD)mops.throwonunmappablechar) << 24);
3752     
3753     if (!IsCLRToNative(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
3754     {
3755         // Unmanaged->managed in/out is the only case where we expect the native buffer to contain valid data.
3756         _ASSERTE((dwFlags & MngdNativeArrayMarshaler::FLAG_NATIVE_DATA_VALID) == 0);
3757         dwFlags |= MngdNativeArrayMarshaler::FLAG_NATIVE_DATA_VALID;
3758     }
3759
3760     pslILEmit->EmitLDC(dwFlags);
3761     
3762     pslILEmit->EmitCALL(METHOD__MNGD_NATIVE_ARRAY_MARSHALER__CREATE_MARSHALER, 3, 0);
3763 }
3764
3765
3766 void ILNativeArrayMarshaler::EmitMarshalArgumentCLRToNative()
3767 {
3768     CONTRACTL
3769     {
3770         STANDARD_VM_CHECK;
3771         PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
3772     }
3773     CONTRACTL_END;
3774
3775     if (UsePinnedArraySpecialCase())
3776     {
3777         //
3778         // Replicate ML_PINNEDISOMORPHICARRAY_C2N_EXPRESS behavior -- note that this
3779         // gives in/out semantics "for free" even if the app doesn't specify one or
3780         // the other.  Since there is no enforcement of this, apps blithely depend
3781         // on it.  
3782         //
3783         
3784         // The base offset should only be 0 for System.Array parameters for which
3785         // OleVariant::GetMarshalerForVarType(vt) should never return NULL.
3786         _ASSERTE(m_pargs->na.m_optionalbaseoffset != 0);
3787
3788         EmitSetupSigAndDefaultHomesCLRToNative();
3789
3790         LocalDesc managedType = GetManagedType();
3791         managedType.MakePinned();
3792
3793         DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedType);
3794         ILCodeLabel* pNullRefLabel = m_pcsMarshal->NewCodeLabel();
3795
3796         m_pcsMarshal->EmitLoadNullPtr();
3797         EmitStoreNativeValue(m_pcsMarshal);
3798
3799         EmitLoadManagedValue(m_pcsMarshal);
3800         m_pcsMarshal->EmitBRFALSE(pNullRefLabel);
3801
3802         EmitLoadManagedValue(m_pcsMarshal);
3803         m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
3804         m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
3805         m_pcsMarshal->EmitCONV_I();
3806         m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
3807         m_pcsMarshal->EmitADD();
3808         EmitStoreNativeValue(m_pcsMarshal);
3809
3810         if (g_pConfig->InteropLogArguments())
3811         {
3812             m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
3813         }
3814
3815         m_pcsMarshal->EmitLabel(pNullRefLabel);
3816     }
3817     else
3818     {
3819         ILMngdMarshaler::EmitMarshalArgumentCLRToNative();
3820     }
3821 }
3822
3823 //
3824 // Peek at the SizeParamIndex argument
3825 // 1) See if the SizeParamIndex argument is being passed by ref
3826 // 2) Get the element type of SizeParamIndex argument
3827 // 
3828 BOOL ILNativeArrayMarshaler::CheckSizeParamIndexArg(
3829     const CREATE_MARSHALER_CARRAY_OPERANDS &mops, 
3830     CorElementType *pElementType)
3831 {
3832     CONTRACTL
3833     {
3834         THROWS;
3835         GC_TRIGGERS;
3836         MODE_ANY;
3837         PRECONDITION(m_pargs != NULL);
3838         PRECONDITION(m_pargs->m_pMarshalInfo != NULL);
3839     }
3840     CONTRACTL_END;
3841
3842     MethodDesc *pMD = m_pargs->m_pMarshalInfo->GetMethodDesc();
3843     _ASSERT(pMD);
3844     
3845     Module *pModule = m_pargs->m_pMarshalInfo->GetModule();
3846     _ASSERT(pModule);
3847
3848     SigTypeContext emptyTypeContext;  // this is an empty type context: ndirect and COM calls are guaranteed to not be generics.
3849     MetaSig msig(pMD->GetSignature(), 
3850                  pModule,
3851                  &emptyTypeContext);
3852
3853     //
3854     // Go to the SizeParamIndex argument
3855     // Note that we already have check in place to make sure SizeParamIndex is within range
3856     //
3857     if (msig.HasExplicitThis()) 
3858         msig.SkipArg();
3859
3860     for (int i = 0; i < mops.countParamIdx; ++i)
3861         msig.SkipArg();
3862
3863     msig.NextArg();
3864     
3865     SigPointer sigPointer = msig.GetArgProps();
3866
3867     // Peek into the SizeParamIndex argument
3868     CorElementType elementType;
3869     IfFailThrow(sigPointer.PeekElemType(&elementType));
3870
3871     if (elementType != ELEMENT_TYPE_BYREF)
3872     {
3873         if (elementType == ELEMENT_TYPE_STRING  ||
3874             elementType == ELEMENT_TYPE_ARRAY   ||
3875             elementType == ELEMENT_TYPE_FNPTR   ||
3876             elementType == ELEMENT_TYPE_OBJECT  ||
3877             elementType == ELEMENT_TYPE_SZARRAY ||
3878             elementType == ELEMENT_TYPE_TYPEDBYREF)
3879         {
3880             COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIZECONTROLBADTYPE);
3881         }
3882         
3883         *pElementType = elementType;
3884         return FALSE;
3885     }
3886
3887     // Get the real type    
3888     IfFailThrow(sigPointer.GetElemType(NULL));
3889     IfFailThrow(sigPointer.PeekElemType(&elementType));
3890
3891     // All the integral types are supported
3892     switch(elementType)
3893     {
3894         case ELEMENT_TYPE_I1:
3895         case ELEMENT_TYPE_U1:
3896         case ELEMENT_TYPE_I2:
3897         case ELEMENT_TYPE_U2:
3898         case ELEMENT_TYPE_I4:
3899         case ELEMENT_TYPE_U4:
3900         case ELEMENT_TYPE_I8:
3901         case ELEMENT_TYPE_U8:
3902         case ELEMENT_TYPE_I:
3903         case ELEMENT_TYPE_U:
3904             break;
3905
3906         default :           
3907             COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIZECONTROLBADTYPE);
3908     }
3909
3910     *pElementType = elementType;
3911     return TRUE;
3912 }
3913
3914 //
3915 // Calculate the number of elements and load it into stack
3916 //
3917 void ILNativeArrayMarshaler::EmitLoadElementCount(ILCodeStream* pslILEmit)
3918 {
3919     STANDARD_VM_CONTRACT;
3920
3921     //
3922     // Determine the element count and load into evaluation stack
3923     //    
3924     CREATE_MARSHALER_CARRAY_OPERANDS mops;
3925     m_pargs->m_pMarshalInfo->GetMops(&mops);
3926
3927     if (mops.multiplier != 0)
3928     {
3929         //
3930         // SizeParamIndex arg fix up for LCID
3931         //
3932         unsigned countParamIdx = mops.countParamIdx;
3933         if (!IsCLRToNative(m_dwMarshalFlags))
3934         {
3935             int lcidParamIdx = m_pslNDirect->GetLCIDParamIdx();
3936     
3937             if (lcidParamIdx >= 0 && (unsigned)lcidParamIdx <= countParamIdx)
3938             {
3939                 // the LCID is injected before the count parameter so the index
3940                 // has to be incremented to get the unmanaged parameter number
3941                 countParamIdx++;
3942             }
3943         }
3944
3945         //
3946         // Load SizeParamIndex argument
3947         //
3948         pslILEmit->EmitLDARG(countParamIdx);
3949
3950         //
3951         // By-Ref support
3952         //
3953         
3954         // Is the SizeParamIndex points to a by-ref parameter?
3955         CorElementType sizeParamIndexArgType; 
3956         if (CheckSizeParamIndexArg(mops, &sizeParamIndexArgType))
3957         {
3958             // Load the by-ref parameter
3959             switch (sizeParamIndexArgType)
3960             {                
3961                 case ELEMENT_TYPE_I1:
3962                     pslILEmit->EmitLDIND_I1();
3963                     break;
3964                     
3965                 case ELEMENT_TYPE_U1:
3966                     pslILEmit->EmitLDIND_U1();
3967                     break;
3968                     
3969                 case ELEMENT_TYPE_I2:
3970                     pslILEmit->EmitLDIND_I2();
3971                     break;
3972                     
3973                 case ELEMENT_TYPE_U2:
3974                     pslILEmit->EmitLDIND_U2();
3975                     break;
3976
3977                 case ELEMENT_TYPE_I4:
3978                     pslILEmit->EmitLDIND_I4();
3979                     break;
3980                     
3981                 case ELEMENT_TYPE_U4:
3982                     pslILEmit->EmitLDIND_U4();
3983                     break;
3984
3985                 case ELEMENT_TYPE_U8:
3986                 case ELEMENT_TYPE_I8:   
3987                     pslILEmit->EmitLDIND_I8();
3988                     break;
3989                     
3990                 case ELEMENT_TYPE_I:
3991                 case ELEMENT_TYPE_U:    
3992                     pslILEmit->EmitLDIND_I();
3993                     break;
3994                     
3995                 default :
3996                     // Should not go here because we should've thrown exception
3997                     _ASSERT(FALSE);
3998             }
3999                 
4000         }
4001
4002         pslILEmit->EmitCONV_OVF_I4();
4003         
4004         // multiplier * arg + additive        
4005         pslILEmit->EmitLDC(mops.multiplier);
4006         pslILEmit->EmitMUL_OVF();
4007         pslILEmit->EmitLDC(mops.additive);
4008         pslILEmit->EmitADD_OVF();
4009     }    
4010     else
4011     {
4012         pslILEmit->EmitLDC((int)mops.additive);
4013     }
4014 }
4015
4016 void ILNativeArrayMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
4017 {
4018     STANDARD_VM_CONTRACT;
4019
4020     EmitLoadMngdMarshaler(pslILEmit);
4021     EmitLoadManagedHomeAddr(pslILEmit);
4022     EmitLoadNativeHomeAddr(pslILEmit);
4023
4024     if (IsByref(m_dwMarshalFlags))
4025     {
4026         //
4027         // Reset the element count just in case there is an exception thrown in the code emitted by
4028         // EmitLoadElementCount. The best thing we can do here is to avoid a crash.
4029         //
4030         _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
4031         pslILEmit->EmitLDC(0);
4032         pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
4033     }
4034
4035     // Dynamically calculate element count using SizeParamIndex argument
4036     EmitLoadElementCount(pslILEmit);
4037
4038     if (IsByref(m_dwMarshalFlags))
4039     {
4040         //
4041         // Save the native array size before converting it to managed and load it again
4042         //
4043         _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
4044         pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
4045         pslILEmit->EmitLDLOC(m_dwSavedSizeArg);
4046     }
4047     
4048     // MngdNativeArrayMarshaler::ConvertSpaceToManaged
4049     pslILEmit->EmitCALL(pslILEmit->GetToken(GetConvertSpaceToManagedMethod()), 4, 0);
4050 }
4051
4052 void ILNativeArrayMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
4053 {
4054     STANDARD_VM_CONTRACT;
4055
4056     if (IsByref(m_dwMarshalFlags))
4057     {
4058         _ASSERTE(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
4059         
4060         //
4061         // Save the array size before converting it to native
4062         //
4063         EmitLoadManagedValue(pslILEmit);
4064         ILCodeLabel *pManagedHomeIsNull = pslILEmit->NewCodeLabel();
4065         pslILEmit->EmitBRFALSE(pManagedHomeIsNull);        
4066         EmitLoadManagedValue(pslILEmit);
4067         pslILEmit->EmitLDLEN();
4068         pslILEmit->EmitSTLOC(m_dwSavedSizeArg);
4069         pslILEmit->EmitLabel(pManagedHomeIsNull);
4070     }
4071
4072         
4073     ILMngdMarshaler::EmitConvertSpaceCLRToNative(pslILEmit);
4074 }
4075
4076 void ILNativeArrayMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
4077 {
4078     STANDARD_VM_CONTRACT;
4079
4080     EmitLoadMngdMarshaler(pslILEmit);
4081     EmitLoadNativeHomeAddr(pslILEmit);
4082     EmitLoadNativeSize(pslILEmit);
4083     
4084     pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeMethod()), 3, 0);
4085 }
4086
4087 void ILNativeArrayMarshaler::EmitLoadNativeSize(ILCodeStream* pslILEmit)
4088 {
4089     STANDARD_VM_CONTRACT;
4090  
4091    if (IsByref(m_dwMarshalFlags))
4092     {
4093         _ASSERT(m_dwSavedSizeArg != LOCAL_NUM_UNUSED);
4094         pslILEmit->EmitLDLOC(m_dwSavedSizeArg);            
4095     }
4096     else
4097     {
4098         pslILEmit->EmitLDC(0);
4099         EmitLoadManagedValue(pslILEmit);
4100         ILCodeLabel *pManagedHomeIsNull = pslILEmit->NewCodeLabel();
4101         pslILEmit->EmitBRFALSE(pManagedHomeIsNull);
4102         pslILEmit->EmitPOP();                       // Pop the 0 on the stack
4103         EmitLoadManagedValue(pslILEmit);       
4104         pslILEmit->EmitLDLEN();
4105         pslILEmit->EmitCONV_OVF_I4();
4106         pslILEmit->EmitLabel(pManagedHomeIsNull);   // Keep the 0 on the stack    
4107     }
4108 }
4109
4110 void ILNativeArrayMarshaler::EmitClearNativeContents(ILCodeStream* pslILEmit)
4111 {
4112     STANDARD_VM_CONTRACT;
4113
4114     EmitLoadMngdMarshaler(pslILEmit);
4115     EmitLoadNativeHomeAddr(pslILEmit);
4116     EmitLoadNativeSize(pslILEmit);
4117    
4118     pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeContentsMethod()), 3, 0);
4119 }
4120
4121 void ILNativeArrayMarshaler::EmitNewSavedSizeArgLocal()
4122 {
4123     STANDARD_VM_CONTRACT;
4124
4125     _ASSERTE(m_dwSavedSizeArg == LOCAL_NUM_UNUSED);
4126     ILCodeStream *pcsSetup = m_pslNDirect->GetSetupCodeStream();
4127     m_dwSavedSizeArg = pcsSetup->NewLocal(ELEMENT_TYPE_I4);
4128     pcsSetup->EmitLDC(0);
4129     pcsSetup->EmitSTLOC(m_dwSavedSizeArg);
4130 }
4131
4132 void ILNativeArrayMarshaler::EmitMarshalArgumentNativeToCLRByref()
4133 {
4134     STANDARD_VM_CONTRACT;
4135
4136     if (IsByref(m_dwMarshalFlags))
4137     {
4138         EmitNewSavedSizeArgLocal();
4139     }
4140     
4141     ILMngdMarshaler::EmitMarshalArgumentNativeToCLRByref();
4142 }
4143
4144 void ILNativeArrayMarshaler::EmitMarshalArgumentCLRToNativeByref()
4145 {
4146     STANDARD_VM_CONTRACT;
4147
4148     if (IsByref(m_dwMarshalFlags))
4149     {
4150         EmitNewSavedSizeArgLocal();
4151     }
4152     
4153     ILMngdMarshaler::EmitMarshalArgumentCLRToNativeByref();
4154 }
4155
4156
4157 #ifndef CROSSGEN_COMPILE
4158
4159 FCIMPL3(void, MngdNativeArrayMarshaler::CreateMarshaler, MngdNativeArrayMarshaler* pThis, MethodTable* pMT, UINT32 dwFlags)
4160 {
4161     FCALL_CONTRACT;
4162
4163     // Don't check whether the input values are negative - passing negative size-controlling
4164     // arguments and compensating them with a positive SizeConst has always worked.
4165     pThis->m_pElementMT            = pMT;
4166     pThis->m_vt                    = (VARTYPE)(dwFlags);
4167     pThis->m_NativeDataValid       = (BYTE)((dwFlags & FLAG_NATIVE_DATA_VALID) != 0);
4168     dwFlags &= ~FLAG_NATIVE_DATA_VALID;
4169     pThis->m_BestFitMap            = (BYTE)(dwFlags >> 16);
4170     pThis->m_ThrowOnUnmappableChar = (BYTE)(dwFlags >> 24);
4171     pThis->m_Array                 = TypeHandle();
4172 }
4173 FCIMPLEND
4174
4175 FCIMPL3(void, MngdNativeArrayMarshaler::ConvertSpaceToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4176 {
4177     FCALL_CONTRACT;
4178
4179     HELPER_METHOD_FRAME_BEGIN_0();
4180    
4181     BASEARRAYREF arrayRef = (BASEARRAYREF) *pManagedHome;
4182
4183     if (arrayRef == NULL)
4184     {
4185         *pNativeHome = NULL;
4186     }
4187     else
4188     {
4189         SIZE_T cElements = arrayRef->GetNumComponents();
4190         SIZE_T cbElement = OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT);
4191
4192         if (cbElement == 0)
4193             COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
4194
4195         SIZE_T cbArray = cElements;
4196         if ( (!SafeMulSIZE_T(&cbArray, cbElement)) || cbArray > MAX_SIZE_FOR_INTEROP)
4197             COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
4198
4199         *pNativeHome = CoTaskMemAlloc(cbArray);
4200         if (*pNativeHome == NULL)
4201             ThrowOutOfMemory();
4202
4203         // initialize the array
4204         FillMemory(*pNativeHome, cbArray, 0);
4205     }
4206
4207     HELPER_METHOD_FRAME_END();
4208 }
4209 FCIMPLEND
4210     
4211 FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToNative, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4212 {
4213     FCALL_CONTRACT;
4214
4215     HELPER_METHOD_FRAME_BEGIN_0();
4216
4217     BASEARRAYREF* pArrayRef = (BASEARRAYREF *) pManagedHome;
4218     
4219     if (*pArrayRef != NULL)
4220     {
4221         const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
4222         SIZE_T cElements = (*pArrayRef)->GetNumComponents();
4223         if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
4224         {
4225             if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
4226                 COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
4227     
4228             _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
4229             memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cElements);
4230         }
4231         else
4232         {
4233             pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap, 
4234                                       pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid, cElements);
4235         }
4236     }
4237     HELPER_METHOD_FRAME_END();
4238 }
4239 FCIMPLEND
4240     
4241 FCIMPL4(void, MngdNativeArrayMarshaler::ConvertSpaceToManaged, MngdNativeArrayMarshaler* pThis,
4242         OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements)
4243 {
4244     FCALL_CONTRACT;
4245
4246     HELPER_METHOD_FRAME_BEGIN_0();
4247
4248     if (*pNativeHome == NULL)
4249     {
4250         SetObjectReference(pManagedHome, NULL, GetAppDomain());
4251     }
4252     else
4253     {
4254         // <TODO>@todo: lookup this class before marshal time</TODO>
4255         if (pThis->m_Array.IsNull())
4256         {
4257             // Get proper array class name & type
4258             pThis->m_Array = OleVariant::GetArrayForVarType(pThis->m_vt, TypeHandle(pThis->m_pElementMT));
4259             if (pThis->m_Array.IsNull())
4260                 COMPlusThrow(kTypeLoadException);
4261         }
4262         //
4263         // Allocate array
4264         //
4265         SetObjectReference(pManagedHome, AllocateArrayEx(pThis->m_Array, &cElements, 1), GetAppDomain());
4266     }    
4267     HELPER_METHOD_FRAME_END();
4268 }
4269 FCIMPLEND
4270     
4271 FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToManaged, MngdNativeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4272 {
4273     FCALL_CONTRACT;
4274
4275     HELPER_METHOD_FRAME_BEGIN_0();
4276     
4277     if (*pNativeHome != NULL)
4278     {
4279         const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
4280     
4281         BASEARRAYREF* pArrayRef = (BASEARRAYREF*) pManagedHome;
4282     
4283         if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
4284         {
4285             SIZE_T cElements = (*pArrayRef)->GetNumComponents();
4286             if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
4287                 COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
4288     
4289                 // If we are copying variants, strings, etc, we need to use write barrier
4290             _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
4291             memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cElements);
4292         }
4293         else
4294         {
4295             pMarshaler->OleToComArray(*pNativeHome, pArrayRef, pThis->m_pElementMT);
4296         }
4297     }
4298     
4299     HELPER_METHOD_FRAME_END();
4300 }
4301 FCIMPLEND
4302
4303 FCIMPL3(void, MngdNativeArrayMarshaler::ClearNative, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
4304 {
4305     FCALL_CONTRACT;
4306
4307     HELPER_METHOD_FRAME_BEGIN_0();
4308     
4309     if (*pNativeHome != NULL)
4310     {
4311         DoClearNativeContents(pThis, pNativeHome, cElements);
4312         CoTaskMemFree(*pNativeHome);
4313     }
4314     
4315     HELPER_METHOD_FRAME_END();
4316 }
4317 FCIMPLEND
4318     
4319 FCIMPL3(void, MngdNativeArrayMarshaler::ClearNativeContents, MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
4320 {
4321     FCALL_CONTRACT;
4322
4323     HELPER_METHOD_FRAME_BEGIN_0();
4324
4325     DoClearNativeContents(pThis, pNativeHome, cElements);
4326     
4327     HELPER_METHOD_FRAME_END();
4328 }
4329 FCIMPLEND
4330
4331 void MngdNativeArrayMarshaler::DoClearNativeContents(MngdNativeArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
4332 {
4333     CONTRACTL
4334     {
4335         THROWS;
4336         GC_TRIGGERS;
4337         MODE_COOPERATIVE;
4338     }
4339     CONTRACTL_END;
4340     
4341     if (*pNativeHome != NULL)
4342     {
4343         const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, FALSE);
4344
4345         if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
4346         {
4347             pMarshaler->ClearOleArray(*pNativeHome, cElements, pThis->m_pElementMT);
4348         }
4349     }
4350 }
4351
4352 #endif // CROSSGEN_COMPILE
4353
4354
4355 #ifdef FEATURE_COMINTEROP
4356 void ILSafeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
4357 {
4358     STANDARD_VM_CONTRACT;
4359
4360     m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
4361         
4362     pslILEmit->EmitLDC(sizeof(MngdSafeArrayMarshaler));
4363     pslILEmit->EmitLOCALLOC();
4364     pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
4365
4366     CREATE_MARSHALER_CARRAY_OPERANDS mops;
4367     m_pargs->m_pMarshalInfo->GetMops(&mops);
4368
4369     DWORD dwFlags = mops.elementType;
4370     BYTE  fStatic = 0;
4371     
4372     if (NeedsCheckForStatic())
4373     {
4374         fStatic |= MngdSafeArrayMarshaler::SCSF_CheckForStatic;
4375     }
4376     
4377     if (!IsCLRToNative(m_dwMarshalFlags) && IsOut(m_dwMarshalFlags) && IsIn(m_dwMarshalFlags))
4378     {
4379         // Unmanaged->managed in/out is the only case where we expect the native buffer to contain valid data.
4380         fStatic |= MngdSafeArrayMarshaler::SCSF_NativeDataValid;
4381     }
4382
4383     dwFlags |= fStatic << 16;
4384     dwFlags |= ((BYTE)!!m_pargs->m_pMarshalInfo->GetNoLowerBounds()) << 24;
4385     
4386     pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
4387     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(mops.methodTable));
4388     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
4389     pslILEmit->EmitLDC(m_pargs->m_pMarshalInfo->GetArrayRank());
4390     pslILEmit->EmitLDC(dwFlags);
4391
4392     pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CREATE_MARSHALER, 4, 0);
4393 }
4394
4395 void ILSafeArrayMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
4396 {
4397     STANDARD_VM_CONTRACT;
4398     
4399     ILMngdMarshaler::EmitConvertContentsNativeToCLR(pslILEmit);
4400
4401     if (NeedsCheckForStatic())
4402     {
4403         CONSISTENCY_CHECK(-1 == m_dwOriginalManagedLocalNum);
4404         m_dwOriginalManagedLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_OBJECT);
4405         EmitLoadManagedValue(pslILEmit);
4406         pslILEmit->EmitSTLOC(m_dwOriginalManagedLocalNum);
4407     }
4408 }
4409
4410 void ILSafeArrayMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
4411 {
4412     STANDARD_VM_CONTRACT;
4413
4414     EmitLoadMngdMarshaler(pslILEmit);
4415     EmitLoadManagedHomeAddr(pslILEmit);
4416     EmitLoadNativeHomeAddr(pslILEmit);
4417     if (NeedsCheckForStatic())
4418     {
4419         CONSISTENCY_CHECK(-1 != m_dwOriginalManagedLocalNum);
4420         pslILEmit->EmitLDLOC(m_dwOriginalManagedLocalNum);
4421     }
4422     else
4423     {
4424         pslILEmit->EmitLDNULL();
4425     }
4426     pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE, 4, 0);
4427 }
4428
4429
4430 #ifndef CROSSGEN_COMPILE
4431
4432 FCIMPL4(void, MngdSafeArrayMarshaler::CreateMarshaler, MngdSafeArrayMarshaler* pThis, MethodTable* pMT, UINT32 iRank, UINT32 dwFlags)
4433 {
4434     FCALL_CONTRACT;
4435
4436     pThis->m_pElementMT    = pMT;
4437     pThis->m_iRank         = iRank;
4438     pThis->m_vt            = (VARTYPE)dwFlags;
4439     pThis->m_fStatic       = (BYTE)(dwFlags >> 16);
4440     pThis->m_nolowerbounds = (BYTE)(dwFlags >> 24);
4441 }
4442 FCIMPLEND
4443
4444 FCIMPL3(void, MngdSafeArrayMarshaler::ConvertSpaceToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4445 {
4446     FCALL_CONTRACT;
4447
4448     if (pThis->m_fStatic & SCSF_IsStatic)
4449         return;
4450     
4451     HELPER_METHOD_FRAME_BEGIN_0();
4452
4453     CONTRACTL
4454     {
4455         THROWS;
4456         GC_TRIGGERS;
4457         MODE_COOPERATIVE;
4458         PRECONDITION(pThis->m_vt != VT_EMPTY);
4459         PRECONDITION(CheckPointer(pThis->m_pElementMT));
4460     }
4461     CONTRACTL_END;
4462     
4463     if (*pManagedHome != NULL)
4464     {
4465         *pNativeHome = (void *) OleVariant::CreateSafeArrayForArrayRef((BASEARRAYREF*) pManagedHome, pThis->m_vt, pThis->m_pElementMT);
4466     }
4467     else
4468     {
4469         *pNativeHome = NULL;
4470     }
4471
4472     HELPER_METHOD_FRAME_END();
4473 }
4474 FCIMPLEND
4475     
4476 FCIMPL4(void, MngdSafeArrayMarshaler::ConvertContentsToNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, Object* pOriginalManagedUNSAFE)
4477 {
4478     CONTRACTL
4479     {
4480         FCALL_CHECK;
4481         PRECONDITION(pThis->m_vt != VT_EMPTY);
4482         PRECONDITION(CheckPointer(pThis->m_pElementMT));
4483     }
4484     CONTRACTL_END;
4485
4486     OBJECTREF pOriginalManaged = ObjectToOBJECTREF(pOriginalManagedUNSAFE);
4487     HELPER_METHOD_FRAME_BEGIN_1(pOriginalManaged);
4488
4489     if ((pThis->m_fStatic & SCSF_IsStatic) &&
4490         (*pManagedHome != pOriginalManaged))
4491     {
4492         COMPlusThrow(kInvalidOperationException, IDS_INVALID_REDIM);
4493     }
4494    
4495     if (*pManagedHome != NULL)
4496     {
4497         OleVariant::MarshalSafeArrayForArrayRef((BASEARRAYREF *) pManagedHome,
4498                                                 (SAFEARRAY*)*pNativeHome,
4499                                                 pThis->m_vt,
4500                                                 pThis->m_pElementMT,
4501                                                 (pThis->m_fStatic & SCSF_NativeDataValid));
4502     }
4503
4504     HELPER_METHOD_FRAME_END();
4505 }
4506 FCIMPLEND
4507     
4508 FCIMPL3(void, MngdSafeArrayMarshaler::ConvertSpaceToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4509 {
4510     CONTRACTL
4511     {
4512         FCALL_CHECK;
4513         PRECONDITION(pThis->m_vt != VT_EMPTY);
4514         PRECONDITION(CheckPointer(pThis->m_pElementMT));
4515     }
4516     CONTRACTL_END;
4517     
4518     HELPER_METHOD_FRAME_BEGIN_0();
4519
4520     if (*pNativeHome != NULL)
4521     {
4522         // If the managed array has a rank defined then make sure the rank of the
4523         // SafeArray matches the defined rank.
4524         if (pThis->m_iRank != -1)
4525         {
4526             int iSafeArrayRank = SafeArrayGetDim((SAFEARRAY*) *pNativeHome);
4527             if (pThis->m_iRank != iSafeArrayRank)
4528             {                    
4529                 WCHAR strExpectedRank[64];
4530                 WCHAR strActualRank[64];
4531                 _ltow_s(pThis->m_iRank, strExpectedRank, COUNTOF(strExpectedRank), 10);
4532                 _ltow_s(iSafeArrayRank, strActualRank, COUNTOF(strActualRank), 10);
4533                 COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYRANKMISMATCH, strActualRank, strExpectedRank);
4534             }
4535         }
4536     
4537         if (pThis->m_nolowerbounds)
4538         {
4539             LONG lowerbound;
4540             if ( (SafeArrayGetDim( (SAFEARRAY*)*pNativeHome ) != 1) ||
4541                  (FAILED(SafeArrayGetLBound( (SAFEARRAY*)*pNativeHome, 1, &lowerbound))) ||
4542                  lowerbound != 0 )
4543             {
4544                 COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
4545             }
4546         }
4547     
4548         SetObjectReference(pManagedHome,
4549             (OBJECTREF) OleVariant::CreateArrayRefForSafeArray((SAFEARRAY*) *pNativeHome,
4550                                                             pThis->m_vt,
4551                                                             pThis->m_pElementMT), GetAppDomain());
4552     }
4553     else
4554     {
4555         SetObjectReference(pManagedHome, NULL, GetAppDomain());
4556     }
4557
4558     HELPER_METHOD_FRAME_END();
4559 }
4560 FCIMPLEND
4561     
4562 FCIMPL3(void, MngdSafeArrayMarshaler::ConvertContentsToManaged, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4563 {
4564     CONTRACTL
4565     {
4566         FCALL_CHECK;
4567         PRECONDITION(pThis->m_vt != VT_EMPTY);
4568         PRECONDITION(CheckPointer(pThis->m_pElementMT));
4569     }
4570     CONTRACTL_END;
4571
4572     SAFEARRAY* pNative = *(SAFEARRAY**)pNativeHome;
4573     HELPER_METHOD_FRAME_BEGIN_0();
4574
4575     if (pNative && pNative->fFeatures & FADF_STATIC)
4576     {
4577         pThis->m_fStatic |= SCSF_IsStatic;
4578     }
4579
4580     if (*pNativeHome != NULL)
4581     {
4582         OleVariant::MarshalArrayRefForSafeArray((SAFEARRAY*)*pNativeHome,
4583                                                 (BASEARRAYREF *) pManagedHome,
4584                                                 pThis->m_vt,
4585                                                 pThis->m_pElementMT);
4586     }
4587     
4588     HELPER_METHOD_FRAME_END();
4589 }
4590 FCIMPLEND
4591     
4592 FCIMPL3(void, MngdSafeArrayMarshaler::ClearNative, MngdSafeArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
4593 {
4594     FCALL_CONTRACT;
4595
4596     if (pThis->m_fStatic & SCSF_IsStatic)
4597         return;
4598
4599     HELPER_METHOD_FRAME_BEGIN_0();
4600
4601     if (*pNativeHome != NULL)
4602     {
4603         GCX_PREEMP();
4604         _ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
4605         // SafeArray has been created.  Oleaut32.dll must have been loaded.
4606         CONTRACT_VIOLATION(ThrowsViolation);
4607         SafeArrayDestroy((SAFEARRAY*)*pNativeHome);
4608     }
4609     
4610     HELPER_METHOD_FRAME_END();
4611 }
4612 FCIMPLEND
4613
4614 #endif // CROSSGEN_COMPILE
4615
4616
4617 LocalDesc ILHiddenLengthArrayMarshaler::GetNativeType()
4618 {
4619     LIMITED_METHOD_CONTRACT;
4620     return LocalDesc(ELEMENT_TYPE_I);
4621 }
4622
4623 LocalDesc ILHiddenLengthArrayMarshaler::GetManagedType()
4624 {
4625     LIMITED_METHOD_CONTRACT;
4626     return LocalDesc(ELEMENT_TYPE_OBJECT);
4627 }
4628
4629 void ILHiddenLengthArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
4630 {
4631     STANDARD_VM_CONTRACT;
4632
4633     if (!CanUsePinnedArray())
4634     {
4635         m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
4636         
4637         pslILEmit->EmitLDC(sizeof(MngdHiddenLengthArrayMarshaler));
4638         pslILEmit->EmitLOCALLOC();
4639         pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
4640
4641         MethodTable *pElementMT = m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().GetMethodTable();
4642         pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);
4643         pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(pElementMT));
4644         pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
4645
4646         pslILEmit->EmitLDC(m_pargs->na.m_cbElementSize);
4647         pslILEmit->EmitLDC(m_pargs->na.m_vt);
4648
4649         pslILEmit->EmitCALL(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CREATE_MARSHALER, 4, 0);
4650     }
4651 }
4652
4653 void ILHiddenLengthArrayMarshaler::EmitMarshalArgumentCLRToNative()
4654 {
4655     STANDARD_VM_CONTRACT;
4656
4657     // If we can pin the array, then do that rather than marshaling it in a more heavy weight way
4658     // Otherwise, fall back to doing a full marshal
4659     if (CanUsePinnedArray())
4660     {
4661         EmitSetupSigAndDefaultHomesCLRToNative();
4662
4663         LocalDesc managedType = GetManagedType();
4664         managedType.MakePinned();
4665         DWORD dwPinnedLocal = m_pcsMarshal->NewLocal(managedType);
4666
4667         ILCodeLabel* pMarshalDoneLabel = m_pcsMarshal->NewCodeLabel();
4668
4669         // native = NULL
4670         m_pcsMarshal->EmitLoadNullPtr();
4671         EmitStoreNativeValue(m_pcsMarshal);
4672
4673         // if (managed == null) goto MarshalDone
4674         EmitLoadManagedValue(m_pcsMarshal);
4675         m_pcsMarshal->EmitBRFALSE(pMarshalDoneLabel);
4676
4677         // pinnedLocal = managed;
4678         EmitLoadManagedValue(m_pcsMarshal);
4679         m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
4680
4681         // native = pinnedLocal + dataOffset
4682         m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
4683         m_pcsMarshal->EmitCONV_I();
4684         m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
4685         m_pcsMarshal->EmitADD();
4686         EmitStoreNativeValue(m_pcsMarshal);
4687
4688         if (g_pConfig->InteropLogArguments())
4689         {
4690             m_pslNDirect->EmitLogNativeArgument(m_pcsMarshal, dwPinnedLocal);
4691         }
4692
4693         // MarshalDone:
4694         m_pcsMarshal->EmitLabel(pMarshalDoneLabel);
4695     }
4696     else
4697     {
4698         ILMngdMarshaler::EmitMarshalArgumentCLRToNative();
4699     }
4700
4701 }
4702
4703 void ILHiddenLengthArrayMarshaler::EmitConvertSpaceNativeToCLR(ILCodeStream* pslILEmit)
4704 {
4705     STANDARD_VM_CONTRACT;
4706
4707     if (!CanUsePinnedArray())
4708     {
4709         EmitLoadMngdMarshaler(pslILEmit);
4710         EmitLoadManagedHomeAddr(pslILEmit);
4711         EmitLoadNativeHomeAddr(pslILEmit);
4712         EmitLoadNativeArrayLength(pslILEmit);
4713         
4714         // MngdHiddenLengthArrayMarshaler::ConvertSpaceToManaged
4715         pslILEmit->EmitCALL(pslILEmit->GetToken(GetConvertSpaceToManagedMethod()), 4, 0);
4716     }
4717 }
4718
4719 void ILHiddenLengthArrayMarshaler::EmitConvertSpaceCLRToNative(ILCodeStream* pslILEmit)
4720 {
4721     STANDARD_VM_CONTRACT;
4722
4723     // If we're marshaling out to native code, then we need to set the length out parameter
4724     if (!IsCLRToNative(m_dwMarshalFlags))
4725     {
4726         if (IsByref(m_dwMarshalFlags) || IsRetval(m_dwMarshalFlags) || IsOut(m_dwMarshalFlags))
4727         {
4728             ILCodeLabel *pSkipGetLengthLabel = m_pcsMarshal->NewCodeLabel();
4729
4730             // nativeLen = 0
4731             pslILEmit->EmitLDC(0);
4732             pslILEmit->EmitCONV_T(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
4733             pslILEmit->EmitSTLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
4734
4735             // if (array == null) goto SkipGetLength
4736             EmitLoadManagedValue(pslILEmit);
4737             pslILEmit->EmitBRFALSE(pSkipGetLengthLabel);
4738
4739             // nativeLen = array.Length
4740             // SkipGetLength:
4741             EmitLoadManagedValue(pslILEmit);
4742             pslILEmit->EmitLDLEN();
4743             pslILEmit->EmitCONV_T(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
4744             pslILEmit->EmitSTLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
4745             pslILEmit->EmitLabel(pSkipGetLengthLabel);
4746
4747             // nativeLenParam = nativeLen
4748             LocalDesc nativeParamType(m_pargs->m_pMarshalInfo->GetHiddenLengthParamElementType());
4749             pslILEmit->EmitLDARG(m_pargs->m_pMarshalInfo->HiddenLengthParamIndex());
4750             pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
4751             pslILEmit->EmitSTIND_T(&nativeParamType);
4752         }
4753     }
4754
4755     if (!CanUsePinnedArray())
4756     {
4757         ILMngdMarshaler::EmitConvertSpaceCLRToNative(pslILEmit);
4758     }
4759 }
4760
4761 void ILHiddenLengthArrayMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
4762 {
4763     STANDARD_VM_CONTRACT;
4764
4765     if (!CanUsePinnedArray())
4766     {
4767         if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE &&
4768             (m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Uri ||
4769              m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs ||
4770              m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs))
4771         {
4772             // System.Uri/NotifyCollectionChangedEventArgs don't live in mscorlib so there's no marshaling helper to call - inline the loop
4773             DWORD dwLoopCounterLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
4774             DWORD dwNativePtrLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
4775             ILCodeLabel *pConditionLabel = pslILEmit->NewCodeLabel();
4776             ILCodeLabel *pLoopBodyLabel = pslILEmit->NewCodeLabel();
4777
4778             // for (IntPtr ptr = pNative, int i = 0; ...
4779             pslILEmit->EmitLDC(0);
4780             pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
4781             EmitLoadNativeValue(pslILEmit);
4782             pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
4783             pslILEmit->EmitBR(pConditionLabel);
4784
4785             // *ptr = EmitConvertCLR*ToWinRT*(pManaged[i]);
4786             pslILEmit->EmitLabel(pLoopBodyLabel);
4787             pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
4788             EmitLoadManagedValue(pslILEmit);
4789             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4790             pslILEmit->EmitLDELEM_REF();
4791
4792             switch (m_pargs->na.m_redirectedTypeIndex)
4793             {
4794                 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
4795                     ILUriMarshaler::EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4796                     break;
4797
4798                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
4799                     ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4800                     break;
4801
4802                 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
4803                     ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4804                     break;
4805
4806                 default: UNREACHABLE();
4807             }
4808
4809             pslILEmit->EmitSTIND_I();
4810
4811             // ... i++, ptr += IntPtr.Size ...
4812             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4813             pslILEmit->EmitLDC(1);
4814             pslILEmit->EmitADD();
4815             pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
4816             pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
4817             pslILEmit->EmitLDC(sizeof(LPVOID));
4818             pslILEmit->EmitADD();
4819             pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
4820
4821             // ... i < pManaged.Length; ...
4822             pslILEmit->EmitLabel(pConditionLabel);
4823             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4824             EmitLoadNativeArrayLength(pslILEmit);
4825             pslILEmit->EmitBLT(pLoopBodyLabel);
4826         }            
4827         else
4828         {
4829             ILMngdMarshaler::EmitConvertContentsCLRToNative(pslILEmit);
4830         }
4831     }
4832 }
4833
4834 void ILHiddenLengthArrayMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
4835 {
4836     STANDARD_VM_CONTRACT;
4837
4838     if (!CanUsePinnedArray())
4839     {
4840         if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE &&
4841             (m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Uri ||
4842              m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs ||
4843              m_pargs->na.m_redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs))
4844         {
4845             // System.Uri/NotifyCollectionChangedEventArgs don't live in mscorlib so there's no marshaling helper to call - inline the loop
4846             DWORD dwLoopCounterLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I4);
4847             DWORD dwNativePtrLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
4848             ILCodeLabel *pConditionLabel = pslILEmit->NewCodeLabel();
4849             ILCodeLabel *pLoopBodyLabel = pslILEmit->NewCodeLabel();
4850
4851             // for (IntPtr ptr = pNative, int i = 0; ...
4852             pslILEmit->EmitLDC(0);
4853             pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
4854             EmitLoadNativeValue(pslILEmit);
4855             pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
4856             pslILEmit->EmitBR(pConditionLabel);
4857
4858             // pManaged[i] = EmitConvertWinRT*ToCLR*(*ptr);
4859             pslILEmit->EmitLabel(pLoopBodyLabel);
4860             EmitLoadManagedValue(pslILEmit);
4861             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4862             pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
4863             pslILEmit->EmitLDIND_I();
4864
4865             switch (m_pargs->na.m_redirectedTypeIndex)
4866             {
4867                 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
4868                     ILUriMarshaler::EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4869                     break;
4870
4871                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
4872                     ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4873                     break;
4874
4875                 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
4876                     ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
4877                     break;
4878
4879                 default: UNREACHABLE();
4880             }
4881             
4882             pslILEmit->EmitSTELEM_REF();
4883
4884             // ... i++, ptr += IntPtr.Size)
4885             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4886             pslILEmit->EmitLDC(1);
4887             pslILEmit->EmitADD();
4888             pslILEmit->EmitSTLOC(dwLoopCounterLocalNum);
4889             pslILEmit->EmitLDLOC(dwNativePtrLocalNum);
4890             pslILEmit->EmitLDC(sizeof(LPVOID));
4891             pslILEmit->EmitADD();
4892             pslILEmit->EmitSTLOC(dwNativePtrLocalNum);
4893
4894             // ... i < pManaged.Length; ...
4895             pslILEmit->EmitLabel(pConditionLabel);
4896             pslILEmit->EmitLDLOC(dwLoopCounterLocalNum);
4897             EmitLoadNativeArrayLength(pslILEmit);
4898             pslILEmit->EmitBLT(pLoopBodyLabel);
4899         }            
4900         else
4901         {
4902             ILMngdMarshaler::EmitConvertContentsNativeToCLR(pslILEmit);
4903         }
4904     }
4905 }
4906
4907 void ILHiddenLengthArrayMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
4908 {
4909     STANDARD_VM_CONTRACT;
4910
4911     EmitClearNativeContents(pslILEmit);
4912
4913     if (!CanUsePinnedArray())
4914     {
4915         EmitLoadNativeValue(pslILEmit);
4916         pslILEmit->EmitCALL(pslILEmit->GetToken(GetClearNativeMethod()), 1, 0);
4917     }
4918 }
4919
4920 void ILHiddenLengthArrayMarshaler::EmitClearNativeContents(ILCodeStream* pslILEmit)
4921 {
4922     STANDARD_VM_CONTRACT;
4923
4924     if (!CanUsePinnedArray())
4925     {
4926         MethodDesc *pMD = GetClearNativeContentsMethod();
4927         if (pMD != NULL)
4928         {
4929             MetaSig sig(pMD);
4930             UINT numArgs = sig.NumFixedArgs();
4931
4932             if (numArgs == 3)
4933             {
4934                 EmitLoadMngdMarshaler(pslILEmit);
4935             }
4936             else
4937             {
4938                 _ASSERTE(numArgs == 2);
4939             }
4940
4941             EmitLoadNativeHomeAddr(pslILEmit);
4942             EmitLoadNativeArrayLength(pslILEmit);
4943             pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), numArgs, 0);
4944         }
4945     }
4946 }
4947
4948 // Determine if we can simply pin the managed array, rather than doing a full marshal
4949 bool ILHiddenLengthArrayMarshaler::CanUsePinnedArray()
4950 {
4951     STANDARD_VM_CONTRACT;
4952
4953     // If the array is only going from managed to native, and it contains only blittable data, and
4954     // we know where that data is located in the array then we can take the fast path
4955     if (!IsCLRToNative(m_dwMarshalFlags))
4956     {
4957         return false;
4958     }
4959
4960     if (m_pargs->na.m_vt != VTHACK_BLITTABLERECORD)
4961     {
4962         return false;
4963     }
4964
4965     if (IsByref(m_dwMarshalFlags))
4966     {
4967         return false;
4968     }
4969
4970     if (!IsIn(m_dwMarshalFlags))
4971     {
4972         return false;
4973     }
4974
4975     if (IsRetval(m_dwMarshalFlags))
4976     {
4977         return false;
4978     }
4979
4980     if (m_pargs->na.m_optionalbaseoffset == 0)
4981     {
4982         return false;
4983     }
4984
4985     return true;
4986 }
4987
4988 void ILHiddenLengthArrayMarshaler::EmitLoadNativeArrayLength(ILCodeStream *pslILEmit)
4989 {
4990     STANDARD_VM_CONTRACT;
4991
4992     // For return values, the native length won't yet be marshaled back to its managed home
4993     // so it needs to be read directly
4994     if (IsRetval(m_dwMarshalFlags))
4995     {
4996         pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthNativeHome());
4997     }
4998     else
4999     {
5000         pslILEmit->EmitLDLOC(m_pargs->m_pMarshalInfo->GetHiddenLengthManagedHome());
5001     }
5002
5003     pslILEmit->EmitCONV_OVF_I4();
5004 }
5005
5006 MethodDesc *ILHiddenLengthArrayMarshaler::GetConvertContentsToManagedMethod()
5007 {
5008     STANDARD_VM_CONTRACT;
5009
5010     if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE)
5011     {
5012         switch (m_pargs->na.m_redirectedTypeIndex)
5013         {
5014             case WinMDAdapter::RedirectedTypeIndex_System_DateTimeOffset:
5015                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_DATETIME);
5016
5017             case WinMDAdapter::RedirectedTypeIndex_System_Type:
5018                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_TYPE);
5019
5020             case WinMDAdapter::RedirectedTypeIndex_System_Exception:
5021                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_EXCEPTION);
5022
5023             case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
5024             {
5025                 MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_NULLABLE);
5026                 return GetExactMarshalerMethod(pMD);
5027             }
5028
5029             case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
5030             {
5031                 MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_MANAGED_KEYVALUEPAIR);
5032                 return GetExactMarshalerMethod(pMD);
5033             }
5034
5035             default:
5036                 UNREACHABLE_MSG("Unrecognized redirected type.");
5037         }
5038     }
5039     return ILMngdMarshaler::GetConvertContentsToManagedMethod();
5040 }
5041
5042 MethodDesc *ILHiddenLengthArrayMarshaler::GetConvertContentsToNativeMethod()
5043 {
5044     STANDARD_VM_CONTRACT;
5045
5046     if (m_pargs->na.m_vt == VTHACK_REDIRECTEDTYPE)
5047     {
5048         switch (m_pargs->na.m_redirectedTypeIndex)
5049         {
5050             case WinMDAdapter::RedirectedTypeIndex_System_DateTimeOffset:
5051                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_DATETIME);
5052
5053             case WinMDAdapter::RedirectedTypeIndex_System_Type:
5054                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_TYPE);
5055
5056             case WinMDAdapter::RedirectedTypeIndex_System_Exception:
5057                 return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_EXCEPTION);
5058
5059             case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
5060             {
5061                 MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_NULLABLE);
5062                 return GetExactMarshalerMethod(pMD);
5063             }
5064
5065             case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
5066             {
5067                 MethodDesc *pMD = MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CONVERT_CONTENTS_TO_NATIVE_KEYVALUEPAIR);
5068                 return GetExactMarshalerMethod(pMD);
5069             }
5070
5071             default:
5072                 UNREACHABLE_MSG("Unrecognized redirected type.");
5073         }
5074     }
5075     return ILMngdMarshaler::GetConvertContentsToNativeMethod();
5076 }
5077
5078 MethodDesc *ILHiddenLengthArrayMarshaler::GetClearNativeContentsMethod()
5079 {
5080     switch (m_pargs->na.m_vt)
5081     {
5082         // HSTRINGs, interface pointers, and non-blittable structs need contents cleanup
5083         case VTHACK_HSTRING:
5084         case VTHACK_INSPECTABLE:
5085         case VTHACK_NONBLITTABLERECORD:
5086             break;
5087
5088         // blittable structs don't need contents cleanup
5089         case VTHACK_BLITTABLERECORD:
5090             return NULL;
5091
5092         case VTHACK_REDIRECTEDTYPE:
5093         {
5094             switch (m_pargs->na.m_redirectedTypeIndex)
5095             {
5096                 // System.Type, Uri, Nullable, KeyValuePair, NCCEventArgs, and PCEventArgs need cleanup
5097                 case WinMDAdapter::RedirectedTypeIndex_System_Type:
5098                     return MscorlibBinder::GetMethod(METHOD__MNGD_HIDDEN_LENGTH_ARRAY_MARSHALER__CLEAR_NATIVE_CONTENTS_TYPE);
5099
5100                 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
5101                 case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
5102                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
5103                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
5104                 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
5105                     break;
5106
5107                 // other redirected types don't
5108                 default:
5109                     return NULL;
5110             }
5111             break;
5112         }
5113
5114         default:
5115             UNREACHABLE_MSG("Unexpected hidden-length array element VT");
5116     }
5117
5118     return ILMngdMarshaler::GetClearNativeContentsMethod();
5119 }
5120
5121 MethodDesc *ILHiddenLengthArrayMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
5122 {
5123     STANDARD_VM_CONTRACT;
5124
5125     return MethodDesc::FindOrCreateAssociatedMethodDesc(
5126         pGenericMD,
5127         pGenericMD->GetMethodTable(),
5128         FALSE,                                 // forceBoxedEntryPoint
5129         m_pargs->na.m_pMT->GetInstantiation(), // methodInst
5130         FALSE,                                 // allowInstParam
5131         TRUE);                                 // forceRemotableMethod
5132 }
5133
5134 #ifndef CROSSGEN_COMPILE
5135
5136 FCIMPL4(void, MngdHiddenLengthArrayMarshaler::CreateMarshaler, MngdHiddenLengthArrayMarshaler* pThis, MethodTable* pMT, SIZE_T cbElementSize, UINT16 vt)
5137 {
5138     FCALL_CONTRACT;
5139
5140     pThis->m_pElementMT = pMT;
5141     pThis->m_cbElementSize = cbElementSize;
5142     pThis->m_vt = (VARTYPE)vt;
5143 }
5144 FCIMPLEND
5145
5146 FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertSpaceToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5147 {
5148     FCALL_CONTRACT;
5149
5150     BASEARRAYREF arrayRef = (BASEARRAYREF) *pManagedHome;
5151     HELPER_METHOD_FRAME_BEGIN_1(arrayRef);
5152
5153     if (arrayRef == NULL)
5154     {
5155         *pNativeHome = NULL;
5156     }
5157     else
5158     {
5159         SIZE_T cbArray = pThis->GetArraySize(arrayRef->GetNumComponents());
5160
5161         *pNativeHome = CoTaskMemAlloc(cbArray);
5162         if (*pNativeHome == NULL)
5163         {
5164             ThrowOutOfMemory();
5165         }
5166
5167         // initialize the array
5168         FillMemory(*pNativeHome, cbArray, 0);
5169     }
5170
5171     HELPER_METHOD_FRAME_END();
5172 }
5173 FCIMPLEND
5174     
5175 FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertContentsToNative, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5176 {
5177     FCALL_CONTRACT;
5178     
5179     struct
5180     {
5181         PTRARRAYREF arrayRef;
5182         STRINGREF currentStringRef;
5183         OBJECTREF currentObjectRef;
5184     }
5185     gc;
5186     ZeroMemory(&gc, sizeof(gc));
5187     gc.arrayRef = (PTRARRAYREF)*pManagedHome;
5188
5189     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
5190
5191     if (gc.arrayRef != NULL)
5192     {
5193         // There are these choices:
5194         //  * the array is made up of entirely blittable data, in which case we can directly copy it, 
5195         //  * it is an array of strings that need to be marshaled as HSTRING, 
5196         //  * it is an array of non-blittable structures
5197         //  * it is an array of interface pointers (interface, runtime class, delegate, System.Object)
5198         switch (pThis->m_vt)
5199         {
5200             case VTHACK_BLITTABLERECORD:
5201             {
5202                 // Just do a raw memcpy into the array
5203                 SIZE_T cbArray = pThis->GetArraySize(gc.arrayRef->GetNumComponents());
5204                 memcpyNoGCRefs(*pNativeHome, gc.arrayRef->GetDataPtr(), cbArray);
5205                 break;
5206             }
5207
5208             case VTHACK_HSTRING:
5209             {
5210                 // Marshal a string array as an array of HSTRINGs
5211                 if (!WinRTSupported())
5212                 {
5213                     COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
5214                 }
5215
5216                 HSTRING *pDestinationStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
5217
5218                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5219                 {
5220                     gc.currentStringRef = (STRINGREF)gc.arrayRef->GetAt(i);
5221                     if (gc.currentStringRef == NULL)
5222                     {
5223                         StackSString ssIndex;
5224                         ssIndex.Printf(W("%d"), i);
5225                         COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHALARRAY_NULL_HSTRING, ssIndex.GetUnicode());
5226                     }
5227
5228                     IfFailThrow(WindowsCreateString(gc.currentStringRef->GetBuffer(), gc.currentStringRef->GetStringLength(), &(pDestinationStrings[i])));
5229                 }
5230                 break;
5231             }
5232
5233             case VTHACK_NONBLITTABLERECORD:
5234             {
5235                 BYTE *pNativeStart = reinterpret_cast<BYTE *>(*pNativeHome);
5236                 SIZE_T managedOffset = ArrayBase::GetDataPtrOffset(gc.arrayRef->GetMethodTable());
5237                 SIZE_T nativeOffset = 0;
5238                 SIZE_T managedSize = gc.arrayRef->GetComponentSize();
5239                 SIZE_T nativeSize = pThis->m_pElementMT->GetNativeSize();
5240                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5241                 {
5242                     LayoutUpdateNative(reinterpret_cast<LPVOID *>(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset, NULL);
5243                     managedOffset += managedSize;
5244                     nativeOffset += nativeSize;
5245                 }
5246                 break;
5247             }
5248
5249             case VTHACK_INSPECTABLE:
5250             {
5251                 // interface pointers
5252                 IUnknown **pDestinationIPs = reinterpret_cast<IUnknown **>(*pNativeHome);
5253                 
5254                 // If this turns out to be a perf issue, we can precompute the ItfMarshalInfo
5255                 // and generate code that passes it to the marshaler at creation time.
5256                 ItfMarshalInfo itfInfo;
5257                 MarshalInfo::GetItfMarshalInfo(TypeHandle(pThis->m_pElementMT), TypeHandle(), FALSE, TRUE, MarshalInfo::MARSHAL_SCENARIO_WINRT, &itfInfo);
5258
5259                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5260                 {
5261                     gc.currentObjectRef = gc.arrayRef->GetAt(i);
5262                     pDestinationIPs[i] = MarshalObjectToInterface(
5263                         &gc.currentObjectRef, 
5264                         itfInfo.thNativeItf.GetMethodTable(),  
5265                         itfInfo.thClass.GetMethodTable(),
5266                         itfInfo.dwFlags);
5267                 }
5268                 break;
5269             }
5270
5271             default:
5272                 UNREACHABLE_MSG("Unrecognized array element VARTYPE");
5273
5274         }
5275     }
5276     HELPER_METHOD_FRAME_END();
5277 }
5278 FCIMPLEND
5279     
5280 FCIMPL4(void, MngdHiddenLengthArrayMarshaler::ConvertSpaceToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome, INT32 cElements)
5281 {
5282     FCALL_CONTRACT;
5283
5284     HELPER_METHOD_FRAME_BEGIN_0();
5285
5286     if (*pNativeHome == NULL)
5287     {
5288         SetObjectReference(pManagedHome, NULL, GetAppDomain());
5289     }
5290     else
5291     {
5292         TypeHandle elementType(pThis->m_pElementMT);
5293         TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing(elementType);
5294         SetObjectReference(pManagedHome, AllocateArrayEx(arrayType, &cElements, 1), GetAppDomain());
5295     }
5296
5297     HELPER_METHOD_FRAME_END();
5298 }
5299 FCIMPLEND
5300     
5301 FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ConvertContentsToManaged, MngdHiddenLengthArrayMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5302 {
5303     FCALL_CONTRACT;
5304
5305     struct
5306     {
5307         PTRARRAYREF arrayRef;
5308         STRINGREF   stringRef;
5309         OBJECTREF   objectRef;
5310     }
5311     gc;
5312     ZeroMemory(&gc, sizeof(gc));
5313     gc.arrayRef = (PTRARRAYREF)*pManagedHome;
5314
5315     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
5316
5317     if (*pNativeHome != NULL)
5318     {
5319         // There are these choices:
5320         //  * the array is made up of entirely blittable data, in which case we can directly copy it, 
5321         //  * it is an array of strings that need to be marshaled as HSTRING, 
5322         //  * it is an array of non-blittable structures
5323         //  * it is an array of interface pointers (interface, runtime class, delegate, System.Object)
5324         switch (pThis->m_vt)
5325         {
5326             case VTHACK_BLITTABLERECORD:
5327             {
5328                 // Just do a raw memcpy into the array
5329                 SIZE_T cbArray = pThis->GetArraySize(gc.arrayRef->GetNumComponents());
5330                 memcpyNoGCRefs(gc.arrayRef->GetDataPtr(), *pNativeHome, cbArray);
5331                 break;
5332             }
5333
5334             case VTHACK_HSTRING:
5335             {
5336                 // Strings are in HSRING format on the native side
5337                 if (!WinRTSupported())
5338                 {
5339                     COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
5340                 }
5341
5342                 HSTRING *pSourceStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
5343
5344                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5345                 {
5346                     // NULL HSTRINGS are equivilent to empty strings
5347                     UINT32 cchString = 0;
5348                     LPCWSTR pwszString = W("");
5349
5350                     if (pSourceStrings[i] != NULL)
5351                     {
5352                         pwszString = WindowsGetStringRawBuffer(pSourceStrings[i], &cchString);
5353                     }
5354
5355                     gc.stringRef = StringObject::NewString(pwszString, cchString);
5356                     gc.arrayRef->SetAt(i, gc.stringRef);
5357                 }
5358                 break;
5359             }
5360
5361             case VTHACK_NONBLITTABLERECORD:
5362             {
5363                 // Defer to the field marshaler to handle structures
5364                 BYTE *pNativeStart = reinterpret_cast<BYTE *>(*pNativeHome);
5365                 SIZE_T managedOffset = ArrayBase::GetDataPtrOffset(gc.arrayRef->GetMethodTable());
5366                 SIZE_T nativeOffset = 0;
5367                 SIZE_T managedSize = gc.arrayRef->GetComponentSize();
5368                 SIZE_T nativeSize = pThis->m_pElementMT->GetNativeSize();
5369                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5370                 {
5371                     LayoutUpdateCLR(reinterpret_cast<LPVOID *>(&gc.arrayRef), managedOffset, pThis->m_pElementMT, pNativeStart + nativeOffset);
5372                     managedOffset += managedSize;
5373                     nativeOffset += nativeSize;
5374                 }
5375                 break;
5376             }
5377
5378             case VTHACK_INSPECTABLE:
5379             {
5380                 // interface pointers
5381                 IUnknown **pSourceIPs = reinterpret_cast<IUnknown **>(*pNativeHome);
5382
5383                 // If this turns out to be a perf issue, we can precompute the ItfMarshalInfo
5384                 // and generate code that passes it to the marshaler at creation time.
5385                 ItfMarshalInfo itfInfo;
5386                 MarshalInfo::GetItfMarshalInfo(TypeHandle(pThis->m_pElementMT), TypeHandle(), FALSE, TRUE, MarshalInfo::MARSHAL_SCENARIO_WINRT, &itfInfo);
5387
5388                 for (SIZE_T i = 0; i < gc.arrayRef->GetNumComponents(); ++i)
5389                 {
5390                     gc.objectRef = gc.arrayRef->GetAt(i);
5391                     UnmarshalObjectFromInterface(
5392                         &gc.objectRef,
5393                         &pSourceIPs[i],
5394                         itfInfo.thItf.GetMethodTable(),  
5395                         itfInfo.thClass.GetMethodTable(),
5396                         itfInfo.dwFlags);
5397                     gc.arrayRef->SetAt(i, gc.objectRef);
5398                 }
5399                 break;
5400             }
5401
5402             default:
5403                 UNREACHABLE_MSG("Unrecognized array element VARTYPE");
5404         }
5405     }
5406     
5407     HELPER_METHOD_FRAME_END();
5408 }
5409 FCIMPLEND
5410
5411 FCIMPL3(void, MngdHiddenLengthArrayMarshaler::ClearNativeContents, MngdHiddenLengthArrayMarshaler* pThis, void** pNativeHome, INT32 cElements)
5412 {
5413     FCALL_CONTRACT;
5414     
5415     HELPER_METHOD_FRAME_BEGIN_0();
5416
5417     if (*pNativeHome != NULL)
5418     {
5419         pThis->DoClearNativeContents(pNativeHome, cElements);
5420     }
5421
5422     HELPER_METHOD_FRAME_END();
5423 }
5424 FCIMPLEND
5425
5426 #endif // CROSSGEN_COMPILE
5427
5428
5429 SIZE_T MngdHiddenLengthArrayMarshaler::GetArraySize(SIZE_T elements)
5430 {
5431     CONTRACTL
5432     {
5433         THROWS;
5434         GC_TRIGGERS;
5435         MODE_COOPERATIVE;
5436     }
5437     CONTRACTL_END;
5438
5439     _ASSERTE_MSG(m_cbElementSize != 0, "You have to set the native size for your array element type");
5440
5441     SIZE_T cbArray;
5442
5443     if (!ClrSafeInt<SIZE_T>::multiply(elements, m_cbElementSize, cbArray))
5444     {
5445         COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
5446     }
5447
5448     // This array size limit is carried over from the equivilent limit for other array marshaling code
5449     if (cbArray > MAX_SIZE_FOR_INTEROP)
5450     {
5451         COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
5452     }
5453
5454     return cbArray;
5455 }
5456
5457 #ifndef CROSSGEN_COMPILE
5458 void MngdHiddenLengthArrayMarshaler::DoClearNativeContents(void** pNativeHome, INT32 cElements)
5459 {
5460     CONTRACTL
5461     {
5462         THROWS;
5463         GC_TRIGGERS;
5464         MODE_COOPERATIVE;
5465         PRECONDITION(pNativeHome != NULL);
5466     }
5467     CONTRACTL_END;
5468
5469     VARTYPE vt = m_vt;
5470     if (vt == VTHACK_REDIRECTEDTYPE)
5471     {
5472         // the redirected types that use this helper are interface pointers on the WinRT side
5473         vt = VTHACK_INSPECTABLE;
5474     }
5475
5476     switch (vt)
5477     {
5478         case VTHACK_HSTRING:
5479         {
5480             if (WinRTSupported())
5481             {
5482                 HSTRING *pStrings = reinterpret_cast<HSTRING *>(*pNativeHome);
5483                 for (INT32 i = 0; i < cElements; ++i)
5484                 {
5485                     if (pStrings[i] != NULL)
5486                     {
5487                         WindowsDeleteString(pStrings[i]);
5488                     }
5489                 }
5490             }
5491             break;
5492         }
5493
5494         case VTHACK_NONBLITTABLERECORD:
5495         {
5496             SIZE_T cbArray = GetArraySize(cElements);
5497             BYTE *pNativeCurrent = reinterpret_cast<BYTE *>(*pNativeHome);
5498             BYTE *pNativeEnd = pNativeCurrent + cbArray;
5499
5500             while (pNativeCurrent < pNativeEnd)
5501             {
5502                 LayoutDestroyNative(pNativeCurrent, m_pElementMT);
5503                 pNativeCurrent += m_pElementMT->GetNativeSize();
5504             }
5505             break;
5506         }
5507     
5508         case VTHACK_INSPECTABLE:
5509         {
5510             IInspectable **pIPs = reinterpret_cast<IInspectable **>(*pNativeHome);
5511             for (INT32 i = 0; i < cElements; ++i)
5512             {
5513                 if (pIPs[i] != NULL)
5514                 {
5515                     SafeRelease(pIPs[i]);
5516                 }
5517             }
5518             break;
5519         }
5520             
5521         default:
5522             UNREACHABLE_MSG("Unexpected hidden-length array element VT");
5523     }    
5524 }
5525 #endif //CROSSGEN_COMPILE
5526 #endif // FEATURE_COMINTEROP
5527
5528 void ILReferenceCustomMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
5529 {
5530     CONTRACTL
5531     {
5532         STANDARD_VM_CHECK;
5533         PRECONDITION(-1 == m_dwMngdMarshalerLocalNum);
5534     }
5535     CONTRACTL_END;
5536     
5537     //
5538     // allocate space for marshaler
5539     //
5540
5541     m_dwMngdMarshalerLocalNum = pslILEmit->NewLocal(ELEMENT_TYPE_I);
5542
5543     pslILEmit->EmitLDC(sizeof(MngdRefCustomMarshaler));
5544     pslILEmit->EmitLOCALLOC();
5545     pslILEmit->EmitSTLOC(m_dwMngdMarshalerLocalNum);
5546
5547     pslILEmit->EmitLDLOC(m_dwMngdMarshalerLocalNum);    // arg to CreateMarshaler
5548     
5549     //
5550     // call CreateCustomMarshalerHelper
5551     //
5552
5553     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->rcm.m_pMD));
5554     pslILEmit->EmitCALL(METHOD__METHOD_HANDLE__GETVALUEINTERNAL, 1, 1);
5555
5556     pslILEmit->EmitLDC(m_pargs->rcm.m_paramToken);
5557
5558     pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(TypeHandle::FromPtr(m_pargs->rcm.m_hndManagedType)));
5559     pslILEmit->EmitCALL(METHOD__RT_TYPE_HANDLE__GETVALUEINTERNAL, 1, 1);
5560
5561     pslILEmit->EmitCALL(METHOD__STUBHELPERS__CREATE_CUSTOM_MARSHALER_HELPER, 3, 1);  // arg to CreateMarshaler
5562
5563     //
5564     // call MngdRefCustomMarshaler::CreateMarshaler
5565     //
5566
5567     pslILEmit->EmitCALL(METHOD__MNGD_REF_CUSTOM_MARSHALER__CREATE_MARSHALER, 2, 0);
5568 }
5569
5570
5571 #ifndef CROSSGEN_COMPILE
5572
5573 FCIMPL2(void, MngdRefCustomMarshaler::CreateMarshaler, MngdRefCustomMarshaler* pThis, void* pCMHelper)
5574 {
5575     FCALL_CONTRACT;
5576
5577     pThis->m_pCMHelper = (CustomMarshalerHelper*)pCMHelper;
5578 }
5579 FCIMPLEND
5580
5581     
5582 FCIMPL3(void, MngdRefCustomMarshaler::ConvertContentsToNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5583 {
5584     CONTRACTL
5585     {
5586         FCALL_CHECK;
5587         PRECONDITION(CheckPointer(pManagedHome));
5588     }
5589     CONTRACTL_END;
5590     
5591     HELPER_METHOD_FRAME_BEGIN_0();
5592
5593     *pNativeHome = pThis->m_pCMHelper->InvokeMarshalManagedToNativeMeth(*pManagedHome);
5594
5595     HELPER_METHOD_FRAME_END();
5596 }
5597 FCIMPLEND
5598     
5599     
5600 FCIMPL3(void, MngdRefCustomMarshaler::ConvertContentsToManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5601 {
5602     CONTRACTL
5603     {
5604         FCALL_CHECK;
5605         PRECONDITION(CheckPointer(pManagedHome));
5606     }
5607     CONTRACTL_END;
5608     
5609     HELPER_METHOD_FRAME_BEGIN_0();
5610
5611     SetObjectReference(pManagedHome, pThis->m_pCMHelper->InvokeMarshalNativeToManagedMeth(*pNativeHome), GetAppDomain());
5612     
5613     HELPER_METHOD_FRAME_END();
5614 }
5615 FCIMPLEND
5616     
5617 FCIMPL3(void, MngdRefCustomMarshaler::ClearNative, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5618 {
5619     FCALL_CONTRACT;
5620
5621     HELPER_METHOD_FRAME_BEGIN_0();
5622
5623     CONTRACTL
5624     {
5625         THROWS;
5626         GC_TRIGGERS;
5627         MODE_ANY;
5628     }
5629     CONTRACTL_END;
5630
5631     pThis->m_pCMHelper->InvokeCleanUpNativeMeth(*pNativeHome);
5632     
5633     HELPER_METHOD_FRAME_END();
5634 }
5635 FCIMPLEND
5636     
5637 FCIMPL3(void, MngdRefCustomMarshaler::ClearManaged, MngdRefCustomMarshaler* pThis, OBJECTREF* pManagedHome, void** pNativeHome)
5638 {
5639     CONTRACTL
5640     {
5641         FCALL_CHECK;
5642         PRECONDITION(CheckPointer(pManagedHome));
5643     }
5644     CONTRACTL_END;
5645
5646     HELPER_METHOD_FRAME_BEGIN_0();
5647     
5648     pThis->m_pCMHelper->InvokeCleanUpManagedMeth(*pManagedHome);
5649     
5650     HELPER_METHOD_FRAME_END();
5651 }
5652 FCIMPLEND
5653
5654 #endif // CROSSGEN_COMPILE
5655
5656
5657 #ifdef FEATURE_COMINTEROP
5658
5659 ///////////////////////////////////////////////////////////////////////////////////////////////////
5660 // ILUriMarshaler implementation
5661 ///////////////////////////////////////////////////////////////////////////////////////////////////
5662
5663 LocalDesc ILUriMarshaler::GetNativeType()
5664 {
5665     LIMITED_METHOD_CONTRACT;
5666     return LocalDesc(ELEMENT_TYPE_I);
5667 }
5668
5669 LocalDesc ILUriMarshaler::GetManagedType()
5670 {
5671     STANDARD_VM_CONTRACT;;    
5672     BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
5673     TypeHandle  hndUriType = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriType();
5674
5675     return LocalDesc(hndUriType); // System.Uri
5676 }
5677
5678 bool ILUriMarshaler::NeedsClearNative()
5679 {
5680     LIMITED_METHOD_CONTRACT;
5681     return true;
5682 }
5683
5684 // Note that this method expects the CLR Uri on top of the evaluation stack and leaves the WinRT Uri there.
5685 //static
5686 void ILUriMarshaler::EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
5687 {
5688     STANDARD_VM_CONTRACT;
5689
5690     UriMarshalingInfo* marshalingInfo = pDomain->GetMarshalingData()->GetUriMarshalingInfo();
5691
5692     ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
5693     ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
5694
5695     pslILEmit->EmitDUP();
5696     pslILEmit->EmitBRTRUE(pNotNullLabel);
5697
5698     pslILEmit->EmitPOP();
5699     pslILEmit->EmitLoadNullPtr();
5700     pslILEmit->EmitBR(pDoneLabel);
5701
5702     pslILEmit->EmitLabel(pNotNullLabel);
5703
5704     // System.Uri.get_OriginalString()
5705     MethodDesc* pSystemUriOriginalStringMD = marshalingInfo->GetSystemUriOriginalStringMD();
5706     pslILEmit->EmitCALL(pslILEmit->GetToken(pSystemUriOriginalStringMD), 1, 1);
5707
5708     pslILEmit->EmitCALL(METHOD__URIMARSHALER__CREATE_NATIVE_URI_INSTANCE, 1, 1);
5709
5710     pslILEmit->EmitLabel(pDoneLabel);
5711 }
5712
5713 void ILUriMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
5714 {
5715     STANDARD_VM_CONTRACT;
5716
5717     EmitLoadManagedValue(pslILEmit);
5718     EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5719     EmitStoreNativeValue(pslILEmit);
5720 }
5721
5722 // Note that this method expects the WinRT Uri on top of the evaluation stack and leaves the CLR Uri there.
5723 //static
5724 void ILUriMarshaler::EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
5725 {
5726     STANDARD_VM_CONTRACT;
5727
5728     MethodDesc* pSystemUriCtorMD = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriCtorMD();
5729
5730     ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
5731     ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
5732
5733     pslILEmit->EmitDUP();
5734     pslILEmit->EmitBRTRUE(pNotNullLabel);
5735
5736     pslILEmit->EmitPOP();
5737     pslILEmit->EmitLDNULL();
5738     pslILEmit->EmitBR(pDoneLabel);
5739
5740     pslILEmit->EmitLabel(pNotNullLabel);
5741
5742     // string UriMarshaler.GetRawUriFromNative(IntPtr)
5743     pslILEmit->EmitCALL(METHOD__URIMARSHALER__GET_RAWURI_FROM_NATIVE, 1, 1);
5744
5745     // System.Uri..ctor(string)
5746     pslILEmit->EmitNEWOBJ(pslILEmit->GetToken(pSystemUriCtorMD), 1);
5747
5748     pslILEmit->EmitLabel(pDoneLabel);
5749 }
5750
5751 void ILUriMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
5752 {
5753     STANDARD_VM_CONTRACT;
5754
5755     EmitLoadNativeValue(pslILEmit);
5756     EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5757     EmitStoreManagedValue(pslILEmit);
5758 }
5759
5760 void ILUriMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
5761 {
5762     STANDARD_VM_CONTRACT;
5763     EmitInterfaceClearNative(pslILEmit);
5764 }
5765
5766 ///////////////////////////////////////////////////////////////////////////////////////////////////
5767 // ILNCCEventArgsMarshaler implementation
5768 ///////////////////////////////////////////////////////////////////////////////////////////////////
5769
5770 LocalDesc ILNCCEventArgsMarshaler::GetNativeType()
5771 {
5772     LIMITED_METHOD_CONTRACT;
5773     return LocalDesc(ELEMENT_TYPE_I);
5774 }
5775
5776 LocalDesc ILNCCEventArgsMarshaler::GetManagedType()
5777 {
5778     STANDARD_VM_CONTRACT;;    
5779     
5780     BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
5781     TypeHandle  hndNCCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsType();
5782
5783     return LocalDesc(hndNCCEventArgType); // System.Collections.Specialized.NotifyCollectionChangedEventArgs
5784 }
5785
5786 bool ILNCCEventArgsMarshaler::NeedsClearNative()
5787 {
5788     LIMITED_METHOD_CONTRACT;
5789     return true;
5790 }
5791
5792 // Note that this method expects the CLR NotifyCollectionChangedEventArgs on top of the evaluation stack and
5793 // leaves the WinRT NotifyCollectionChangedEventArgs IP there.
5794 //static
5795 void ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
5796 {
5797     STANDARD_VM_CONTRACT;
5798
5799     MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsToWinRTNCCEventArgsMD();
5800
5801     // IntPtr System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToNative(NotifyCollectionChangedEventArgs)
5802     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
5803 }
5804
5805 void ILNCCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslILEmit)
5806 {
5807     STANDARD_VM_CONTRACT;
5808
5809     EmitLoadManagedValue(pslILEmit);
5810     EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5811     EmitStoreNativeValue(pslILEmit);
5812 }
5813
5814 // Note that this method expects the WinRT NotifyCollectionChangedEventArgs on top of the evaluation stack and
5815 // leaves the CLR NotifyCollectionChangedEventArgs there.
5816 //static
5817 void ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
5818 {
5819     STANDARD_VM_CONTRACT;
5820
5821     MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
5822
5823     // NotifyCollectionChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
5824     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
5825 }
5826
5827 void ILNCCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
5828 {
5829     STANDARD_VM_CONTRACT;
5830
5831     EmitLoadNativeValue(pslILEmit);
5832     EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5833     EmitStoreManagedValue(pslILEmit);
5834 }
5835
5836 void ILNCCEventArgsMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
5837 {
5838     STANDARD_VM_CONTRACT;
5839     EmitInterfaceClearNative(pslILEmit);
5840 }
5841
5842 ///////////////////////////////////////////////////////////////////////////////////////////////////
5843 // ILPCEventArgsMarshaler implementation
5844 ///////////////////////////////////////////////////////////////////////////////////////////////////
5845
5846 LocalDesc ILPCEventArgsMarshaler::GetNativeType()
5847 {
5848     LIMITED_METHOD_CONTRACT;
5849     return LocalDesc(ELEMENT_TYPE_I);
5850 }
5851
5852 LocalDesc ILPCEventArgsMarshaler::GetManagedType()
5853 {
5854     STANDARD_VM_CONTRACT;;    
5855     
5856     BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
5857     TypeHandle  hndPCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsType();
5858
5859     return LocalDesc(hndPCEventArgType); // System.ComponentModel.PropertyChangedEventArgs
5860 }
5861
5862 bool ILPCEventArgsMarshaler::NeedsClearNative()
5863 {
5864     LIMITED_METHOD_CONTRACT;
5865     return true;
5866 }
5867
5868 // Note that this method expects the CLR PropertyChangedEventArgs on top of the evaluation stack and
5869 // leaves the WinRT PropertyChangedEventArgs IP there.
5870 //static
5871 void ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
5872 {
5873     STANDARD_VM_CONTRACT;
5874
5875     MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsToWinRTPCEventArgsMD();
5876
5877     // IntPtr System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToNative(PropertyChangedEventArgs)
5878     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
5879 }
5880
5881 void ILPCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslILEmit)
5882 {
5883     STANDARD_VM_CONTRACT;
5884
5885     EmitLoadManagedValue(pslILEmit);
5886     EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5887     EmitStoreNativeValue(pslILEmit);
5888 }
5889
5890 // Note that this method expects the WinRT PropertyChangedEventArgs on top of the evaluation stack and
5891 // leaves the CLR PropertyChangedEventArgs there.
5892 //static
5893 void ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
5894 {
5895     STANDARD_VM_CONTRACT;
5896
5897     MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTPCEventArgsToSystemPCEventArgsMD();
5898
5899     // PropertyChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
5900     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
5901 }
5902
5903 void ILPCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
5904 {
5905     STANDARD_VM_CONTRACT;
5906
5907     EmitLoadNativeValue(pslILEmit);
5908     EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
5909     EmitStoreManagedValue(pslILEmit);
5910 }
5911
5912 void ILPCEventArgsMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
5913 {
5914     STANDARD_VM_CONTRACT;
5915     EmitInterfaceClearNative(pslILEmit);
5916 }
5917
5918 ///////////////////////////////////////////////////////////////////////////////////////////////////
5919 // ILDateTimeMarshaler implementation
5920 ///////////////////////////////////////////////////////////////////////////////////////////////////
5921
5922 LocalDesc ILDateTimeMarshaler::GetNativeType()
5923 {
5924     STANDARD_VM_CONTRACT;;    
5925     return LocalDesc(MscorlibBinder::GetClass(CLASS__DATETIMENATIVE));
5926 }
5927
5928 LocalDesc ILDateTimeMarshaler::GetManagedType()
5929 {
5930     STANDARD_VM_CONTRACT;;    
5931     return LocalDesc(MscorlibBinder::GetClass(CLASS__DATE_TIME_OFFSET));
5932 }
5933
5934 bool ILDateTimeMarshaler::NeedsClearNative()
5935 {
5936     LIMITED_METHOD_CONTRACT;
5937     return false;
5938 }
5939
5940 void ILDateTimeMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
5941 {
5942     CONTRACTL
5943     {
5944         STANDARD_VM_CHECK;
5945         PRECONDITION(CheckPointer(pslILEmit));
5946     }
5947     CONTRACTL_END;
5948
5949     // DateTimeOffsetMarshaler.ConvertManagedToNative(ref managedDTO, out nativeTicks);
5950     EmitLoadManagedHomeAddr(pslILEmit);
5951     EmitLoadNativeHomeAddr(pslILEmit);    
5952     pslILEmit->EmitCALL(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE, 2, 0);
5953 }
5954
5955 void ILDateTimeMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
5956 {
5957     STANDARD_VM_CONTRACT;
5958
5959     // DateTimeOffsetMarshaler.ConvertNativeToManaged(out managedLocalDTO, ref nativeTicks);
5960     EmitLoadManagedHomeAddr(pslILEmit);
5961     EmitLoadNativeHomeAddr(pslILEmit);
5962     pslILEmit->EmitCALL(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED, 2, 0);
5963 }
5964
5965 void ILDateTimeMarshaler::EmitReInitNative(ILCodeStream* pslILEmit)
5966 {
5967     STANDARD_VM_CONTRACT;
5968
5969     EmitLoadNativeHomeAddr(pslILEmit);
5970     pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__DATETIMENATIVE)));
5971 }
5972
5973 ///////////////////////////////////////////////////////////////////////////////////////////////////
5974 // ILNullableMarshaler implementation
5975 ///////////////////////////////////////////////////////////////////////////////////////////////////
5976
5977 LocalDesc ILNullableMarshaler::GetNativeType()
5978 {
5979     LIMITED_METHOD_CONTRACT;
5980     return LocalDesc(ELEMENT_TYPE_I);
5981 }
5982
5983 LocalDesc ILNullableMarshaler::GetManagedType()
5984 {
5985     LIMITED_METHOD_CONTRACT;;    
5986     return LocalDesc(m_pargs->m_pMT);
5987 }
5988
5989 bool ILNullableMarshaler::NeedsClearNative()
5990 {
5991     LIMITED_METHOD_CONTRACT;
5992     return true;
5993 }
5994
5995 void ILNullableMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
5996 {
5997     CONTRACTL
5998     {
5999         STANDARD_VM_CHECK;
6000         PRECONDITION(CheckPointer(pslILEmit));
6001     }
6002     CONTRACTL_END;
6003     
6004     // pNative = NullableMarshaler<T>.ConvertToNative(ref pManaged);
6005     EmitLoadManagedHomeAddr(pslILEmit);
6006
6007     MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE));
6008     pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
6009
6010     EmitStoreNativeValue(pslILEmit);
6011 }
6012
6013 void ILNullableMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
6014 {
6015     STANDARD_VM_CONTRACT;
6016
6017     // pManaged = NullableMarshaler.ConvertToManaged(pNative);
6018     EmitLoadNativeValue(pslILEmit);
6019
6020     MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED));
6021     pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
6022
6023     EmitStoreManagedValue(pslILEmit);
6024 }
6025
6026 void ILNullableMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
6027 {
6028     STANDARD_VM_CONTRACT;
6029     EmitInterfaceClearNative(pslILEmit);
6030 }
6031
6032 MethodDesc *ILNullableMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
6033 {
6034     STANDARD_VM_CONTRACT;
6035
6036     return MethodDesc::FindOrCreateAssociatedMethodDesc(
6037         pGenericMD,
6038         pGenericMD->GetMethodTable(),
6039         FALSE,                              // forceBoxedEntryPoint
6040         m_pargs->m_pMT->GetInstantiation(), // methodInst
6041         FALSE,                              // allowInstParam
6042         TRUE);                              // forceRemotableMethod
6043 }
6044
6045 ///////////////////////////////////////////////////////////////////////////////////////////////////
6046 // ILSystemTypeMarshaler implementation
6047 ///////////////////////////////////////////////////////////////////////////////////////////////////
6048
6049 LocalDesc ILSystemTypeMarshaler::GetNativeType()
6050 {
6051     STANDARD_VM_CONTRACT;
6052     
6053     return LocalDesc(MscorlibBinder::GetClass(CLASS__TYPENAMENATIVE));
6054 }
6055
6056 LocalDesc ILSystemTypeMarshaler::GetManagedType()
6057 {
6058     STANDARD_VM_CONTRACT;
6059     
6060     return LocalDesc(MscorlibBinder::GetClass(CLASS__TYPE));
6061 }
6062
6063 bool ILSystemTypeMarshaler::NeedsClearNative()
6064 {
6065     LIMITED_METHOD_CONTRACT;
6066     return true;
6067 }
6068
6069 void ILSystemTypeMarshaler::EmitConvertContentsCLRToNative(ILCodeStream * pslILEmit)
6070 {
6071     STANDARD_VM_CONTRACT;
6072
6073     // SystemTypeMarshaler.ConvertToNative(Type, pTypeName);    
6074     EmitLoadManagedValue(pslILEmit);
6075     EmitLoadNativeHomeAddr(pslILEmit);
6076     pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE, 2, 0);
6077 }
6078
6079 void ILSystemTypeMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream * pslILEmit)
6080 {
6081     STANDARD_VM_CONTRACT;
6082     
6083     // type = SystemTypeMarshaler.ConvertNativeToManaged(pTypeName, ref Type);
6084     EmitLoadNativeHomeAddr(pslILEmit);
6085     EmitLoadManagedHomeAddr(pslILEmit);
6086     pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED, 2, 0);
6087 }
6088
6089
6090 void ILSystemTypeMarshaler::EmitClearNative(ILCodeStream * pslILEmit)
6091 {
6092     STANDARD_VM_CONTRACT;
6093     
6094     // SystemTypeMarshaler.ClearNative(pTypeName)
6095     EmitLoadNativeHomeAddr(pslILEmit);
6096     pslILEmit->EmitCALL(METHOD__SYSTEMTYPEMARSHALER__CLEAR_NATIVE, 1, 0);
6097 }
6098
6099 void ILSystemTypeMarshaler::EmitReInitNative(ILCodeStream * pslILEmit)
6100 {
6101     EmitLoadNativeHomeAddr(pslILEmit);
6102     pslILEmit->EmitINITOBJ(pslILEmit->GetToken(MscorlibBinder::GetClass(CLASS__TYPENAMENATIVE)));
6103 }
6104
6105 ///////////////////////////////////////////////////////////////////////////////////////////////////
6106 // ILHResultExceptionMarshaler implementation
6107 ///////////////////////////////////////////////////////////////////////////////////////////////////
6108
6109 LocalDesc ILHResultExceptionMarshaler::GetNativeType()
6110 {
6111     LIMITED_METHOD_CONTRACT;
6112     return LocalDesc(ELEMENT_TYPE_I4);
6113 }
6114
6115 LocalDesc ILHResultExceptionMarshaler::GetManagedType()
6116 {
6117     LIMITED_METHOD_CONTRACT;
6118     _ASSERTE(m_pargs->m_pMT != NULL);
6119     return LocalDesc(m_pargs->m_pMT);
6120 }
6121
6122 bool ILHResultExceptionMarshaler::NeedsClearNative()
6123 {
6124     LIMITED_METHOD_CONTRACT;
6125     return false;
6126 }
6127
6128 void ILHResultExceptionMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
6129 {
6130     CONTRACTL
6131     {
6132         STANDARD_VM_CHECK;
6133         PRECONDITION(CheckPointer(pslILEmit));
6134     }
6135     CONTRACTL_END;
6136     
6137     // int HResultExceptionMarshaler.ConvertManagedToNative(Exception);
6138     EmitLoadManagedValue(pslILEmit);
6139     pslILEmit->EmitCALL(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE, 1, 1);
6140     EmitStoreNativeValue(pslILEmit);
6141 }
6142
6143 void ILHResultExceptionMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
6144 {
6145     CONTRACTL
6146     {
6147         STANDARD_VM_CHECK;
6148         PRECONDITION(CheckPointer(pslILEmit));
6149     }
6150     CONTRACTL_END;
6151
6152     // Exception HResultExceptionMarshaler.ConvertNativeToManaged(int hr);
6153     EmitLoadNativeValue(pslILEmit);
6154     pslILEmit->EmitCALL(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED, 1, 1);
6155     EmitStoreManagedValue(pslILEmit);
6156 }
6157
6158 ///////////////////////////////////////////////////////////////////////////////////////////////////
6159 // ILKeyValuePairMarshaler implementation
6160 ///////////////////////////////////////////////////////////////////////////////////////////////////
6161
6162 LocalDesc ILKeyValuePairMarshaler::GetNativeType()
6163 {
6164     LIMITED_METHOD_CONTRACT;
6165     return LocalDesc(ELEMENT_TYPE_I);
6166 }
6167
6168 LocalDesc ILKeyValuePairMarshaler::GetManagedType()
6169 {
6170     LIMITED_METHOD_CONTRACT;;    
6171     return LocalDesc(m_pargs->m_pMT);
6172 }
6173
6174 bool ILKeyValuePairMarshaler::NeedsClearNative()
6175 {
6176     LIMITED_METHOD_CONTRACT;
6177     return true;
6178 }
6179
6180 void ILKeyValuePairMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
6181 {
6182     STANDARD_VM_CONTRACT;
6183     
6184     // Native = KeyValueMarshaler<K, V>.ConvertToNative([In] ref Managed);
6185     EmitLoadManagedHomeAddr(pslILEmit);
6186
6187     MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__KEYVALUEPAIRMARSHALER__CONVERT_TO_NATIVE));
6188     pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
6189
6190     EmitStoreNativeValue(pslILEmit);    
6191 }
6192
6193 void ILKeyValuePairMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
6194 {
6195     STANDARD_VM_CONTRACT;
6196
6197     // Managed = KeyValuePairMarshaler<K, V>.ConvertToManaged(Native);
6198     EmitLoadNativeValue(pslILEmit);
6199
6200     MethodDesc *pMD = GetExactMarshalerMethod(MscorlibBinder::GetMethod(METHOD__KEYVALUEPAIRMARSHALER__CONVERT_TO_MANAGED));
6201     pslILEmit->EmitCALL(pslILEmit->GetToken(pMD), 1, 1);
6202
6203     EmitStoreManagedValue(pslILEmit);    
6204 }
6205
6206 void ILKeyValuePairMarshaler::EmitClearNative(ILCodeStream* pslILEmit)
6207 {
6208     STANDARD_VM_CONTRACT;
6209     EmitInterfaceClearNative(pslILEmit);
6210 }
6211
6212 MethodDesc *ILKeyValuePairMarshaler::GetExactMarshalerMethod(MethodDesc *pGenericMD)
6213 {
6214     STANDARD_VM_CONTRACT;
6215
6216     // KeyValuePairMarshaler methods are generic - find/create the exact method.
6217     return MethodDesc::FindOrCreateAssociatedMethodDesc(
6218         pGenericMD,
6219         pGenericMD->GetMethodTable(),
6220         FALSE,                              // forceBoxedEntryPoint
6221         m_pargs->m_pMT->GetInstantiation(), // methodInst
6222         FALSE,                              // allowInstParam
6223         TRUE);                              // forceRemotableMethod
6224 }
6225
6226 #endif  // FEATURE_COMINTEROP