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