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