summaryrefslogtreecommitdiff
path: root/src/vm/clrvarargs.cpp
blob: d58a2e8b615128a1a22e63d177d3fbd8c97beaba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// 
// File: CLRVarArgs.cpp
//

//
// Variant-specific marshalling.


#include "common.h"
#include "clrvarargs.h"

DWORD VARARGS::CalcVaListSize(VARARGS *data)
{
    LIMITED_METHOD_CONTRACT;

    // Calculate how much space we need for the marshaled stack. 
    // This assumes that the vararg managed and unmanaged calling conventions are similar-enough, 
    // so we can simply use the size stored in the VASigCookie. This actually overestimates
    // the value since it counts the fixed args as well as the varargs. But that's harmless.

    DWORD dwVaListSize = data->ArgCookie->sizeOfArgs;
#ifndef _TARGET_X86_
    dwVaListSize += ARGUMENTREGISTERS_SIZE;
#endif
    return dwVaListSize;
}

void VARARGS::MarshalToManagedVaList(va_list va, VARARGS *dataout)
{
    WRAPPER_NO_CONTRACT

#ifndef PLATFORM_UNIX
    _ASSERTE(dataout != NULL);
    dataout->SigPtr = SigPointer(NULL, 0);
    dataout->ArgCookie = NULL;
    dataout->ArgPtr = (BYTE*)va;
#else
    PORTABILITY_ASSERT("Implement for Unix");
#endif
}

////////////////////////////////////////////////////////////////////////////////
// Marshal a ArgIterator to a pre-allocated va_list
////////////////////////////////////////////////////////////////////////////////
void 
VARARGS::MarshalToUnmanagedVaList(
    va_list va, DWORD cbVaListSize, const VARARGS * data)
{
#ifndef PLATFORM_UNIX
    BYTE * pdstbuffer = (BYTE *)va;

    int    remainingArgs = data->RemainingArgs;
    BYTE * psrc = (BYTE *)(data->ArgPtr);
    BYTE * pdst = pdstbuffer;
    
    SigPointer sp = data->SigPtr;
    SigTypeContext typeContext; // This is an empty type context.  This is OK because the vararg methods may not be generic
    while (remainingArgs--) 
    {
        CorElementType elemType = sp.PeekElemTypeClosed(data->ArgCookie->pModule, &typeContext); 
        switch (elemType)
        {
            case ELEMENT_TYPE_I1:
            case ELEMENT_TYPE_U1:
            case ELEMENT_TYPE_I2:
            case ELEMENT_TYPE_U2:
            case ELEMENT_TYPE_I4:
            case ELEMENT_TYPE_U4:
            case ELEMENT_TYPE_I8:
            case ELEMENT_TYPE_U8:
            case ELEMENT_TYPE_R4:
            case ELEMENT_TYPE_R8:
            case ELEMENT_TYPE_I:
            case ELEMENT_TYPE_U:
            case ELEMENT_TYPE_PTR:
                {
                    DWORD cbSize = StackElemSize(CorTypeInfo::Size(elemType));

                    #ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
                    if (cbSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
                        cbSize = sizeof(void*);
                    #endif
                    
#ifdef _TARGET_ARM_
                    if (cbSize == 8)
                    {
                        // 64-bit primitives come from and must be copied to 64-bit aligned locations.
                        psrc = (BYTE*)ALIGN_UP(psrc, 8);
                        pdst = (BYTE*)ALIGN_UP(pdst, 8);
                    }
#endif // _TARGET_ARM_

                    #ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
                    psrc -= cbSize;
                    #endif // STACK_GROWS_DOWN_ON_ARGS_WALK

                    if (pdst + cbSize > pdstbuffer + cbVaListSize)
                        COMPlusThrow(kArgumentException);
                    
                    CopyMemory(pdst, psrc, cbSize);

                    #ifdef STACK_GROWS_UP_ON_ARGS_WALK
                    psrc += cbSize;
                    #endif // STACK_GROWS_UP_ON_ARGS_WALK

                    pdst += cbSize;
                    IfFailThrow(sp.SkipExactlyOne());
                }
                break;

            default:
                // non-IJW data type - we don't support marshaling these inside a va_list.
                COMPlusThrow(kNotSupportedException);
        }
    }
#else
    PORTABILITY_ASSERT("Implement for Unix");
#endif
} // VARARGS::MarshalToUnmanagedVaList