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: CLRVarArgs.cpp
6//
7
8//
9// Variant-specific marshalling.
10
11
12#include "common.h"
13#include "clrvarargs.h"
14
15DWORD VARARGS::CalcVaListSize(VARARGS *data)
16{
17 LIMITED_METHOD_CONTRACT;
18
19 // Calculate how much space we need for the marshaled stack.
20 // This assumes that the vararg managed and unmanaged calling conventions are similar-enough,
21 // so we can simply use the size stored in the VASigCookie. This actually overestimates
22 // the value since it counts the fixed args as well as the varargs. But that's harmless.
23
24 DWORD dwVaListSize = data->ArgCookie->sizeOfArgs;
25#ifndef _TARGET_X86_
26 dwVaListSize += ARGUMENTREGISTERS_SIZE;
27#endif
28 return dwVaListSize;
29}
30
31void VARARGS::MarshalToManagedVaList(va_list va, VARARGS *dataout)
32{
33 WRAPPER_NO_CONTRACT
34
35#ifndef PLATFORM_UNIX
36 _ASSERTE(dataout != NULL);
37 dataout->SigPtr = SigPointer(NULL, 0);
38 dataout->ArgCookie = NULL;
39 dataout->ArgPtr = (BYTE*)va;
40#else
41 PORTABILITY_ASSERT("Implement for Unix");
42#endif
43}
44
45////////////////////////////////////////////////////////////////////////////////
46// Marshal a ArgIterator to a pre-allocated va_list
47////////////////////////////////////////////////////////////////////////////////
48void
49VARARGS::MarshalToUnmanagedVaList(
50 va_list va, DWORD cbVaListSize, const VARARGS * data)
51{
52#ifndef PLATFORM_UNIX
53 BYTE * pdstbuffer = (BYTE *)va;
54
55 int remainingArgs = data->RemainingArgs;
56 BYTE * psrc = (BYTE *)(data->ArgPtr);
57 BYTE * pdst = pdstbuffer;
58
59 SigPointer sp = data->SigPtr;
60 SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
61 while (remainingArgs--)
62 {
63 CorElementType elemType = sp.PeekElemTypeClosed(data->ArgCookie->pModule, &typeContext);
64 switch (elemType)
65 {
66 case ELEMENT_TYPE_I1:
67 case ELEMENT_TYPE_U1:
68 case ELEMENT_TYPE_I2:
69 case ELEMENT_TYPE_U2:
70 case ELEMENT_TYPE_I4:
71 case ELEMENT_TYPE_U4:
72 case ELEMENT_TYPE_I8:
73 case ELEMENT_TYPE_U8:
74 case ELEMENT_TYPE_R4:
75 case ELEMENT_TYPE_R8:
76 case ELEMENT_TYPE_I:
77 case ELEMENT_TYPE_U:
78 case ELEMENT_TYPE_PTR:
79 {
80 DWORD cbSize = StackElemSize(CorTypeInfo::Size(elemType));
81
82 #ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
83 if (cbSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
84 cbSize = sizeof(void*);
85 #endif
86
87#ifdef _TARGET_ARM_
88 if (cbSize == 8)
89 {
90 // 64-bit primitives come from and must be copied to 64-bit aligned locations.
91 psrc = (BYTE*)ALIGN_UP(psrc, 8);
92 pdst = (BYTE*)ALIGN_UP(pdst, 8);
93 }
94#endif // _TARGET_ARM_
95
96 #ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
97 psrc -= cbSize;
98 #endif // STACK_GROWS_DOWN_ON_ARGS_WALK
99
100 if (pdst + cbSize > pdstbuffer + cbVaListSize)
101 COMPlusThrow(kArgumentException);
102
103 CopyMemory(pdst, psrc, cbSize);
104
105 #ifdef STACK_GROWS_UP_ON_ARGS_WALK
106 psrc += cbSize;
107 #endif // STACK_GROWS_UP_ON_ARGS_WALK
108
109 pdst += cbSize;
110 IfFailThrow(sp.SkipExactlyOne());
111 }
112 break;
113
114 default:
115 // non-IJW data type - we don't support marshaling these inside a va_list.
116 COMPlusThrow(kNotSupportedException);
117 }
118 }
119#else
120 PORTABILITY_ASSERT("Implement for Unix");
121#endif
122} // VARARGS::MarshalToUnmanagedVaList
123