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