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 | |
15 | DWORD 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 | |
31 | void 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 | //////////////////////////////////////////////////////////////////////////////// |
48 | void |
49 | VARARGS::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 | |