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 
6 //
7 // This file is a line by line port of callingconvention.h from the desktop CLR. See reference source in the ReferenceSource directory
8 //
9 #if ARM
10 #define _TARGET_ARM_
11 #define CALLDESCR_ARGREGS                          // CallDescrWorker has ArgumentRegister parameter
12 #define CALLDESCR_FPARGREGS                        // CallDescrWorker has FloatArgumentRegisters parameter
13 #define ENREGISTERED_RETURNTYPE_MAXSIZE
14 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
15 #define FEATURE_HFA
16 #elif ARM64
17 #define _TARGET_ARM64_
18 #define CALLDESCR_ARGREGS                          // CallDescrWorker has ArgumentRegister parameter
19 #define CALLDESCR_FPARGREGS                        // CallDescrWorker has FloatArgumentRegisters parameter
20 #define ENREGISTERED_RETURNTYPE_MAXSIZE
21 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
22 #define ENREGISTERED_PARAMTYPE_MAXSIZE
23 #define FEATURE_HFA
24 #elif X86
25 #define _TARGET_X86_
26 #define ENREGISTERED_RETURNTYPE_MAXSIZE
27 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
28 #define CALLDESCR_ARGREGS                          // CallDescrWorker has ArgumentRegister parameter
29 #elif AMD64
30 #if UNIXAMD64
31 #define UNIX_AMD64_ABI
32 #define CALLDESCR_ARGREGS                          // CallDescrWorker has ArgumentRegister parameter
33 #else
34 #endif
35 #define CALLDESCR_FPARGREGS                        // CallDescrWorker has FloatArgumentRegisters parameter
36 #define _TARGET_AMD64_
37 #define ENREGISTERED_RETURNTYPE_MAXSIZE
38 #define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
39 #define ENREGISTERED_PARAMTYPE_MAXSIZE
40 #elif WASM
41 #define _TARGET_WASM_
42 #else
43 #error Unknown architecture!
44 #endif
45 
46 // Provides an abstraction over platform specific calling conventions (specifically, the calling convention
47 // utilized by the JIT on that platform). The caller enumerates each argument of a signature in turn, and is
48 // provided with information mapping that argument into registers and/or stack locations.
49 
50 using System;
51 using System.Collections.Generic;
52 using System.Diagnostics;
53 using Internal.Runtime;
54 using Internal.Runtime.Augments;
55 using Internal.Runtime.TypeLoader;
56 using Internal.NativeFormat;
57 
58 namespace Internal.Runtime.CallConverter
59 {
60     public enum CallingConvention
61     {
62         ManagedInstance,
63         ManagedStatic,
64         StdCall,
65         /*FastCall, CDecl */
66     }
67 
68     public static class CallingConventionInfo
69     {
TypeUsesReturnBuffer(RuntimeTypeHandle returnType, bool methodWithReturnTypeIsVarArg)70         public static bool TypeUsesReturnBuffer(RuntimeTypeHandle returnType, bool methodWithReturnTypeIsVarArg)
71         {
72             TypeHandle thReturnType = new TypeHandle(false, returnType);
73             CorElementType typeReturnType = thReturnType.GetCorElementType();
74 
75             bool usesReturnBuffer;
76             uint fpReturnSizeIgnored;
77             ArgIterator.ComputeReturnValueTreatment(typeReturnType, thReturnType, methodWithReturnTypeIsVarArg, out usesReturnBuffer, out fpReturnSizeIgnored);
78 
79             return usesReturnBuffer;
80         }
81     }
82 
83     internal unsafe struct TypeHandle
84     {
TypeHandleInternal.Runtime.CallConverter.TypeHandle85         public TypeHandle(bool isByRef, RuntimeTypeHandle eeType)
86         {
87             _eeType = eeType.ToEETypePtr();
88             _isByRef = isByRef;
89 
90             if (_eeType->IsByRefType)
91             {
92                 Debug.Assert(_isByRef == false); // ByRef to ByRef isn't valid
93                 _isByRef = true;
94                 _eeType = _eeType->RelatedParameterType;
95             }
96         }
97 
98         private readonly EEType* _eeType;
99         private readonly bool _isByRef;
100 
EqualsInternal.Runtime.CallConverter.TypeHandle101         public bool Equals(TypeHandle other)
102         {
103             return _isByRef == other._isByRef && _eeType == other._eeType;
104         }
105 
GetHashCodeInternal.Runtime.CallConverter.TypeHandle106         public override int GetHashCode() { return (int)_eeType->HashCode; }
107 
IsNullInternal.Runtime.CallConverter.TypeHandle108         public bool IsNull() { return _eeType == null && !_isByRef; }
IsValueTypeInternal.Runtime.CallConverter.TypeHandle109         public bool IsValueType() { if (_isByRef) return false; return _eeType->IsValueType; }
110 
GetSizeInternal.Runtime.CallConverter.TypeHandle111         public unsafe uint GetSize()
112         {
113             if (IsValueType())
114                 return _eeType->ValueTypeSize;
115             else
116                 return (uint)IntPtr.Size;
117         }
118 
RequiresAlign8Internal.Runtime.CallConverter.TypeHandle119         public bool RequiresAlign8()
120         {
121 #if !ARM
122             return false;
123 #else
124             if (_isByRef)
125             {
126                 return false;
127             }
128             return _eeType->RequiresAlign8;
129 #endif
130         }
IsHFAInternal.Runtime.CallConverter.TypeHandle131         public bool IsHFA()
132         {
133 #if !ARM && !ARM64
134             return false;
135 #else
136             if (_isByRef)
137             {
138                 return false;
139             }
140             return _eeType->IsHFA;
141 #endif
142         }
143 
GetHFATypeInternal.Runtime.CallConverter.TypeHandle144         public CorElementType GetHFAType()
145         {
146             Debug.Assert(IsHFA());
147 #if ARM
148             if (RequiresAlign8())
149             {
150                 return CorElementType.ELEMENT_TYPE_R8;
151             }
152 #elif ARM64
153             if (_eeType->FieldAlignmentRequirement == IntPtr.Size)
154             {
155                 return CorElementType.ELEMENT_TYPE_R8;
156             }
157 #endif
158             return CorElementType.ELEMENT_TYPE_R4;
159         }
160 
GetCorElementTypeInternal.Runtime.CallConverter.TypeHandle161         public CorElementType GetCorElementType()
162         {
163             if (_isByRef)
164             {
165                 return CorElementType.ELEMENT_TYPE_BYREF;
166             }
167 
168             // The core redhawk runtime has a slightly different concept of what CorElementType should be for a type. It matches for primitive and enum types
169             // but for other types, it doesn't match the needs in this file.
170             CorElementType rhCorElementType = _eeType->CorElementType;
171 
172             if (((rhCorElementType >= CorElementType.ELEMENT_TYPE_BOOLEAN) && (rhCorElementType <= CorElementType.ELEMENT_TYPE_R8)) ||
173                     (rhCorElementType == CorElementType.ELEMENT_TYPE_I) ||
174                     (rhCorElementType == CorElementType.ELEMENT_TYPE_U))
175             {
176                 return rhCorElementType; // If Redhawk thinks the corelementtype is a primitive type, then it agree with the concept of corelement type needed in this codebase.
177             }
178             else if (_eeType == typeof(void).TypeHandle.ToEETypePtr())
179             {
180                 return CorElementType.ELEMENT_TYPE_VOID;
181             }
182             else if (IsValueType())
183             {
184                 return CorElementType.ELEMENT_TYPE_VALUETYPE;
185             }
186             else if (_eeType->IsPointerType)
187             {
188                 return CorElementType.ELEMENT_TYPE_PTR;
189             }
190             else
191             {
192                 return CorElementType.ELEMENT_TYPE_CLASS;
193             }
194         }
195 
196         private static int[] s_elemSizes = new int[]
197             {
198                 0, //ELEMENT_TYPE_END          0x0
199                 0, //ELEMENT_TYPE_VOID         0x1
200                 1, //ELEMENT_TYPE_BOOLEAN      0x2
201                 2, //ELEMENT_TYPE_CHAR         0x3
202                 1, //ELEMENT_TYPE_I1           0x4
203                 1, //ELEMENT_TYPE_U1           0x5
204                 2, //ELEMENT_TYPE_I2           0x6
205                 2, //ELEMENT_TYPE_U2           0x7
206                 4, //ELEMENT_TYPE_I4           0x8
207                 4, //ELEMENT_TYPE_U4           0x9
208                 8, //ELEMENT_TYPE_I8           0xa
209                 8, //ELEMENT_TYPE_U8           0xb
210                 4, //ELEMENT_TYPE_R4           0xc
211                 8, //ELEMENT_TYPE_R8           0xd
212                 -2,//ELEMENT_TYPE_STRING       0xe
213                 -2,//ELEMENT_TYPE_PTR          0xf
214                 -2,//ELEMENT_TYPE_BYREF        0x10
215                 -1,//ELEMENT_TYPE_VALUETYPE    0x11
216                 -2,//ELEMENT_TYPE_CLASS        0x12
217                 0, //ELEMENT_TYPE_VAR          0x13
218                 -2,//ELEMENT_TYPE_ARRAY        0x14
219                 0, //ELEMENT_TYPE_GENERICINST  0x15
220                 0, //ELEMENT_TYPE_TYPEDBYREF   0x16
221                 0, // UNUSED                   0x17
222                 -2,//ELEMENT_TYPE_I            0x18
223                 -2,//ELEMENT_TYPE_U            0x19
224                 0, // UNUSED                   0x1a
225                 -2,//ELEMENT_TYPE_FPTR         0x1b
226                 -2,//ELEMENT_TYPE_OBJECT       0x1c
227                 -2,//ELEMENT_TYPE_SZARRAY      0x1d
228             };
229 
GetElemSizeInternal.Runtime.CallConverter.TypeHandle230         unsafe public static int GetElemSize(CorElementType t, TypeHandle thValueType)
231         {
232             if (((int)t) <= 0x1d)
233             {
234                 int elemSize = s_elemSizes[(int)t];
235                 if (elemSize == -1)
236                 {
237                     return (int)thValueType.GetSize();
238                 }
239                 if (elemSize == -2)
240                 {
241                     return IntPtr.Size;
242                 }
243                 return elemSize;
244             }
245             return 0;
246         }
247 
GetRuntimeTypeHandleInternal.Runtime.CallConverter.TypeHandle248         public RuntimeTypeHandle GetRuntimeTypeHandle() { return _eeType->ToRuntimeTypeHandle(); }
249     }
250 
251     // Describes how a single argument is laid out in registers and/or stack locations when given as an input to a
252     // managed method as part of a larger signature.
253     //
254     // Locations are split into floating point registers, general registers and stack offsets. Registers are
255     // obviously architecture dependent but are represented as a zero-based index into the usual sequence in which
256     // such registers are allocated for input on the platform in question. For instance:
257     //      X86: 0 == ecx, 1 == edx
258     //      ARM: 0 == r0, 1 == r1, 2 == r2 etc.
259     //
260     // Stack locations are represented as offsets from the stack pointer (at the point of the call). The offset is
261     // given as an index of a pointer sized slot. Similarly the size of data on the stack is given in slot-sized
262     // units. For instance, given an index of 2 and a size of 3:
263     //      X86:   argument starts at [ESP + 8] and is 12 bytes long
264     //      AMD64: argument starts at [RSP + 16] and is 24 bytes long
265     //
266     // The structure is flexible enough to describe an argument that is split over several (consecutive) registers
267     // and possibly on to the stack as well.
268     internal struct ArgLocDesc
269     {
270         public int m_idxFloatReg;  // First floating point register used (or -1)
271         public int m_cFloatReg;    // Count of floating point registers used (or 0)
272 
273         public int m_idxGenReg;    // First general register used (or -1)
274         public int m_cGenReg;      // Count of general registers used (or 0)
275 
276         public int m_idxStack;     // First stack slot used (or -1)
277         public int m_cStack;       // Count of stack slots used (or 0)
278 
279 #if _TARGET_ARM64_
280         public bool m_isSinglePrecision;        // For determining if HFA is single or double precision
281 #endif
282 
283 #if _TARGET_ARM_
284         public bool m_fRequires64BitAlignment;  // True if the argument should always be aligned (in registers or on the stack
285 #endif
286 
287         // Initialize to represent a non-placed argument (no register or stack slots referenced).
InitInternal.Runtime.CallConverter.ArgLocDesc288         public void Init()
289         {
290             m_idxFloatReg = -1;
291             m_cFloatReg = 0;
292             m_idxGenReg = -1;
293             m_cGenReg = 0;
294             m_idxStack = -1;
295             m_cStack = 0;
296 
297 #if _TARGET_ARM64_
298             m_isSinglePrecision = false;
299 #endif
300 
301 #if _TARGET_ARM_
302             m_fRequires64BitAlignment = false;
303 #endif
304         }
305     };
306 
307     internal class ArgIteratorData
308     {
ArgIteratorData(bool hasThis, bool isVarArg, TypeHandle[] parameterTypes, TypeHandle returnType)309         public ArgIteratorData(bool hasThis,
310                         bool isVarArg,
311                         TypeHandle[] parameterTypes,
312                         TypeHandle returnType)
313         {
314             _hasThis = hasThis;
315             _isVarArg = isVarArg;
316             _parameterTypes = parameterTypes;
317             _returnType = returnType;
318         }
319 
320         private bool _hasThis;
321         private bool _isVarArg;
322         private TypeHandle[] _parameterTypes;
323         private TypeHandle _returnType;
324 
Equals(object obj)325         public override bool Equals(object obj)
326         {
327             if (this == obj) return true;
328 
329             ArgIteratorData other = obj as ArgIteratorData;
330             if (other == null) return false;
331 
332             if (_hasThis != other._hasThis || _isVarArg != other._isVarArg || !_returnType.Equals(other._returnType))
333                 return false;
334 
335             if (_parameterTypes == null)
336                 return other._parameterTypes == null;
337 
338             if (other._parameterTypes == null || _parameterTypes.Length != other._parameterTypes.Length)
339                 return false;
340 
341             for (int i = 0; i < _parameterTypes.Length; i++)
342                 if (!_parameterTypes[i].Equals(other._parameterTypes[i]))
343                     return false;
344 
345             return true;
346         }
347 
GetHashCode()348         public override int GetHashCode()
349         {
350             return 37 + (_parameterTypes == null ?
351                 _returnType.GetHashCode() :
352                 TypeHashingAlgorithms.ComputeGenericInstanceHashCode(_returnType.GetHashCode(), _parameterTypes));
353         }
354 
HasThis()355         public bool HasThis() { return _hasThis; }
IsVarArg()356         public bool IsVarArg() { return _isVarArg; }
NumFixedArgs()357         public int NumFixedArgs() { return _parameterTypes != null ? _parameterTypes.Length : 0; }
358 
359         // Argument iteration.
GetArgumentType(int argNum, out TypeHandle thArgType)360         public CorElementType GetArgumentType(int argNum, out TypeHandle thArgType)
361         {
362             thArgType = _parameterTypes[argNum];
363             CorElementType returnValue = thArgType.GetCorElementType();
364             return returnValue;
365         }
366 
GetByRefArgumentType(int argNum)367         public TypeHandle GetByRefArgumentType(int argNum)
368         {
369             return (argNum < _parameterTypes.Length && _parameterTypes[argNum].GetCorElementType() == CorElementType.ELEMENT_TYPE_BYREF) ?
370                 _parameterTypes[argNum] :
371                 default(TypeHandle);
372         }
373 
GetReturnType(out TypeHandle thRetType)374         public CorElementType GetReturnType(out TypeHandle thRetType)
375         {
376             thRetType = _returnType;
377             return thRetType.GetCorElementType();
378         }
379 
380 #if CCCONVERTER_TRACE
GetEETypeDebugName(int argNum)381         public string GetEETypeDebugName(int argNum)
382         {
383             Internal.TypeSystem.TypeSystemContext context = TypeSystemContextFactory.Create();
384             var result = context.ResolveRuntimeTypeHandle(_parameterTypes[argNum].GetRuntimeTypeHandle()).ToString();
385             TypeSystemContextFactory.Recycle(context);
386             return result;
387         }
388 #endif
389     }
390 
391     //-----------------------------------------------------------------------
392     // ArgIterator is helper for dealing with calling conventions.
393     // It is tightly coupled with TransitionBlock. It uses offsets into
394     // TransitionBlock to represent argument locations for efficiency
395     // reasons. Alternatively, it can also return ArgLocDesc for less
396     // performance critical code.
397     //
398     // The ARGITERATOR_BASE argument of the template is provider of the parsed
399     // method signature. Typically, the arg iterator works on top of MetaSig.
400     // Reflection invoke uses alternative implementation to save signature parsing
401     // time because of it has the parsed signature available.
402     //-----------------------------------------------------------------------
403     //template<class ARGITERATOR_BASE>
404     internal unsafe struct ArgIterator //: public ARGITERATOR_BASE
405     {
406         private bool _hasThis;
407         private bool _hasParamType;
408         private bool _extraFunctionPointerArg;
409         private ArgIteratorData _argData;
410         private bool[] _forcedByRefParams;
411         private bool _skipFirstArg;
412         private bool _extraObjectFirstArg;
413         private CallingConvention _interpreterCallingConvention;
414 
HasThisInternal.Runtime.CallConverter.ArgIterator415         public bool HasThis() { return _hasThis; }
IsVarArgInternal.Runtime.CallConverter.ArgIterator416         public bool IsVarArg() { return _argData.IsVarArg(); }
HasParamTypeInternal.Runtime.CallConverter.ArgIterator417         public bool HasParamType() { return _hasParamType; }
NumFixedArgsInternal.Runtime.CallConverter.ArgIterator418         public int NumFixedArgs() { return _argData.NumFixedArgs() + (_extraFunctionPointerArg ? 1 : 0) + (_extraObjectFirstArg ? 1 : 0); }
419 
420         // Argument iteration.
GetArgumentTypeInternal.Runtime.CallConverter.ArgIterator421         public CorElementType GetArgumentType(int argNum, out TypeHandle thArgType, out bool forceByRefReturn)
422         {
423             forceByRefReturn = false;
424 
425             if (_extraObjectFirstArg && argNum == 0)
426             {
427                 thArgType = new TypeHandle(false, typeof(object).TypeHandle);
428                 return CorElementType.ELEMENT_TYPE_CLASS;
429             }
430 
431             argNum = _extraObjectFirstArg ? argNum - 1 : argNum;
432             Debug.Assert(argNum >= 0);
433 
434             if (_forcedByRefParams != null && (argNum + 1) < _forcedByRefParams.Length)
435                 forceByRefReturn = _forcedByRefParams[argNum + 1];
436 
437             if (_extraFunctionPointerArg && argNum == _argData.NumFixedArgs())
438             {
439                 thArgType = new TypeHandle(false, typeof(IntPtr).TypeHandle);
440                 return CorElementType.ELEMENT_TYPE_I;
441             }
442 
443             return _argData.GetArgumentType(argNum, out thArgType);
444         }
445 
GetReturnTypeInternal.Runtime.CallConverter.ArgIterator446         public CorElementType GetReturnType(out TypeHandle thRetType, out bool forceByRefReturn)
447         {
448             if (_forcedByRefParams != null && _forcedByRefParams.Length > 0)
449                 forceByRefReturn = _forcedByRefParams[0];
450             else
451                 forceByRefReturn = false;
452 
453             return _argData.GetReturnType(out thRetType);
454         }
455 
456 #if CCCONVERTER_TRACE
GetEETypeDebugNameInternal.Runtime.CallConverter.ArgIterator457         public string GetEETypeDebugName(int argNum)
458         {
459             if (_extraObjectFirstArg && argNum == 0)
460                 return "System.Object";
461             return _argData.GetEETypeDebugName(_extraObjectFirstArg ? argNum - 1 : argNum);
462         }
463 #endif
464 
ResetInternal.Runtime.CallConverter.ArgIterator465         public void Reset()
466         {
467             _argType = default(CorElementType);
468             _argTypeHandle = default(TypeHandle);
469             _argSize = 0;
470             _argNum = 0;
471             _argForceByRef = false;
472             _ITERATION_STARTED = false;
473         }
474 
475         //public:
476         //------------------------------------------------------------
477         // Constructor
478         //------------------------------------------------------------
ArgIteratorInternal.Runtime.CallConverter.ArgIterator479         public ArgIterator(ArgIteratorData argData, CallingConvention callConv, bool hasParamType, bool extraFunctionPointerArg, bool[] forcedByRefParams, bool skipFirstArg, bool extraObjectFirstArg)
480         {
481             this = default(ArgIterator);
482             _argData = argData;
483             _hasThis = callConv == CallingConvention.ManagedInstance;
484             _hasParamType = hasParamType;
485             _extraFunctionPointerArg = extraFunctionPointerArg;
486             _forcedByRefParams = forcedByRefParams;
487             _skipFirstArg = skipFirstArg;
488             _extraObjectFirstArg = extraObjectFirstArg;
489             _interpreterCallingConvention = callConv;
490         }
491 
SetHasParamTypeAndResetInternal.Runtime.CallConverter.ArgIterator492         public void SetHasParamTypeAndReset(bool value)
493         {
494             _hasParamType = value;
495             Reset();
496         }
497 
SetHasThisAndResetInternal.Runtime.CallConverter.ArgIterator498         public void SetHasThisAndReset(bool value)
499         {
500             _hasThis = value;
501             Reset();
502         }
503 
SizeOfArgStackInternal.Runtime.CallConverter.ArgIterator504         private uint SizeOfArgStack()
505         {
506             //        WRAPPER_NO_CONTRACT;
507             if (!_SIZE_OF_ARG_STACK_COMPUTED)
508                 ForceSigWalk();
509             Debug.Assert(_SIZE_OF_ARG_STACK_COMPUTED);
510             return (uint)_nSizeOfArgStack;
511         }
512 
513         // For use with ArgIterator. This function computes the amount of additional
514         // memory required above the TransitionBlock.  The parameter offsets
515         // returned by ArgIterator::GetNextOffset are relative to a
516         // FramedMethodFrame, and may be in either of these regions.
SizeOfFrameArgumentArrayInternal.Runtime.CallConverter.ArgIterator517         public int SizeOfFrameArgumentArray()
518         {
519             //        WRAPPER_NO_CONTRACT;
520 
521             uint size = SizeOfArgStack();
522 
523 #if _TARGET_AMD64_ && !UNIX_AMD64_ABI
524             // The argument registers are not included in the stack size on AMD64
525             size += ArchitectureConstants.ARGUMENTREGISTERS_SIZE;
526 #endif
527 
528             return (int)size;
529         }
530 
531         //------------------------------------------------------------------------
532 
533 #if _TARGET_X86_
CbStackPopInternal.Runtime.CallConverter.ArgIterator534         public int CbStackPop()
535         {
536             //        WRAPPER_NO_CONTRACT;
537 
538             if (this.IsVarArg())
539                 return 0;
540             else
541                 return (int)SizeOfArgStack();
542         }
543 #endif
544 
545         // Is there a hidden parameter for the return parameter?
546         //
HasRetBuffArgInternal.Runtime.CallConverter.ArgIterator547         public bool HasRetBuffArg()
548         {
549             //        WRAPPER_NO_CONTRACT;
550             if (!_RETURN_FLAGS_COMPUTED)
551                 ComputeReturnFlags();
552             return _RETURN_HAS_RET_BUFFER;
553         }
554 
GetFPReturnSizeInternal.Runtime.CallConverter.ArgIterator555         public uint GetFPReturnSize()
556         {
557             //        WRAPPER_NO_CONTRACT;
558             if (!_RETURN_FLAGS_COMPUTED)
559                 ComputeReturnFlags();
560             return _fpReturnSize;
561         }
562 
563 #if _TARGET_X86_
564         //=========================================================================
565         // Indicates whether an argument is to be put in a register using the
566         // default IL calling convention. This should be called on each parameter
567         // in the order it appears in the call signature. For a non-static meethod,
568         // this function should also be called once for the "this" argument, prior
569         // to calling it for the "real" arguments. Pass in a typ of ELEMENT_TYPE_CLASS.
570         //
571         //  *pNumRegistersUsed:  [in,out]: keeps track of the number of argument
572         //                       registers assigned previously. The caller should
573         //                       initialize this variable to 0 - then each call
574         //                       will update it.
575         //
576         //  typ:                 the signature type
577         //=========================================================================
IsArgumentInRegisterInternal.Runtime.CallConverter.ArgIterator578         private static bool IsArgumentInRegister(ref int pNumRegistersUsed, CorElementType typ, TypeHandle thArgType)
579         {
580             //        LIMITED_METHOD_CONTRACT;
581             if ((pNumRegistersUsed) < ArchitectureConstants.NUM_ARGUMENT_REGISTERS)
582             {
583                 switch (typ)
584                 {
585                     case CorElementType.ELEMENT_TYPE_BOOLEAN:
586                     case CorElementType.ELEMENT_TYPE_CHAR:
587                     case CorElementType.ELEMENT_TYPE_I1:
588                     case CorElementType.ELEMENT_TYPE_U1:
589                     case CorElementType.ELEMENT_TYPE_I2:
590                     case CorElementType.ELEMENT_TYPE_U2:
591                     case CorElementType.ELEMENT_TYPE_I4:
592                     case CorElementType.ELEMENT_TYPE_U4:
593                     case CorElementType.ELEMENT_TYPE_STRING:
594                     case CorElementType.ELEMENT_TYPE_PTR:
595                     case CorElementType.ELEMENT_TYPE_BYREF:
596                     case CorElementType.ELEMENT_TYPE_CLASS:
597                     case CorElementType.ELEMENT_TYPE_ARRAY:
598                     case CorElementType.ELEMENT_TYPE_I:
599                     case CorElementType.ELEMENT_TYPE_U:
600                     case CorElementType.ELEMENT_TYPE_FNPTR:
601                     case CorElementType.ELEMENT_TYPE_OBJECT:
602                     case CorElementType.ELEMENT_TYPE_SZARRAY:
603                         pNumRegistersUsed++;
604                         return true;
605 
606                     case CorElementType.ELEMENT_TYPE_VALUETYPE:
607                         {
608                             // On ProjectN valuetypes of integral size are passed enregistered
609                             int structSize = TypeHandle.GetElemSize(typ, thArgType);
610                             switch (structSize)
611                             {
612                                 case 1:
613                                 case 2:
614                                 case 4:
615                                     pNumRegistersUsed++;
616                                     return true;
617                             }
618                             break;
619                         }
620                 }
621             }
622 
623             return (false);
624         }
625 #endif // _TARGET_X86_
626 
627 #if ENREGISTERED_PARAMTYPE_MAXSIZE
628 
629         // Note that this overload does not handle varargs
IsArgPassedByRefInternal.Runtime.CallConverter.ArgIterator630         private static bool IsArgPassedByRef(TypeHandle th)
631         {
632             //        LIMITED_METHOD_CONTRACT;
633 
634             Debug.Assert(!th.IsNull());
635 
636             // This method only works for valuetypes. It includes true value types,
637             // primitives, enums and TypedReference.
638             Debug.Assert(th.IsValueType());
639 
640             uint size = th.GetSize();
641 #if _TARGET_AMD64_
642             return IsArgPassedByRef((int)size);
643 #elif _TARGET_ARM64_
644             // Composites greater than 16 bytes are passed by reference
645             return ((size > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE) && !th.IsHFA());
646 #else
647 #error ArgIterator::IsArgPassedByRef
648 #endif
649         }
650 
651 #if _TARGET_AMD64_
652         // This overload should only be used in AMD64-specific code only.
IsArgPassedByRefInternal.Runtime.CallConverter.ArgIterator653         private static bool IsArgPassedByRef(int size)
654         {
655             //        LIMITED_METHOD_CONTRACT;
656 
657             // If the size is bigger than ENREGISTERED_PARAM_TYPE_MAXSIZE, or if the size is NOT a power of 2, then
658             // the argument is passed by reference.
659             return (size > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE) || ((size & (size - 1)) != 0);
660         }
661 #endif
662 
663         // This overload should be used for varargs only.
IsVarArgPassedByRefInternal.Runtime.CallConverter.ArgIterator664         private static bool IsVarArgPassedByRef(int size)
665         {
666             //        LIMITED_METHOD_CONTRACT;
667 
668 #if _TARGET_AMD64_
669             return IsArgPassedByRef(size);
670 #else
671             return (size > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE);
672 #endif
673         }
674 #endif // ENREGISTERED_PARAMTYPE_MAXSIZE
675 
IsArgPassedByRefInternal.Runtime.CallConverter.ArgIterator676         public bool IsArgPassedByRef()
677         {
678             //        LIMITED_METHOD_CONTRACT;
679             if (IsArgForcedPassedByRef())
680             {
681                 return true;
682             }
683 
684             if (_argType == CorElementType.ELEMENT_TYPE_BYREF)
685             {
686                 return true;
687             }
688 #if ENREGISTERED_PARAMTYPE_MAXSIZE
689 #if _TARGET_AMD64_
690             return IsArgPassedByRef(_argSize);
691 #elif _TARGET_ARM64_
692             if (_argType == CorElementType.ELEMENT_TYPE_VALUETYPE)
693             {
694                 Debug.Assert(!_argTypeHandle.IsNull());
695                 return ((_argSize > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE) && (!_argTypeHandle.IsHFA() || IsVarArg()));
696             }
697             return false;
698 #else
699 #error PORTABILITY_ASSERT("ArgIterator::IsArgPassedByRef");
700 #endif
701 #else // ENREGISTERED_PARAMTYPE_MAXSIZE
702             return false;
703 #endif // ENREGISTERED_PARAMTYPE_MAXSIZE
704         }
705 
IsArgForcedPassedByRefInternal.Runtime.CallConverter.ArgIterator706         private bool IsArgForcedPassedByRef()
707         {
708             // This should be true for valuetypes instantiated over T in a generic signature using universal shared generic calling convention
709             return _argForceByRef;
710         }
711 
712         //------------------------------------------------------------
713         // Return the offsets of the special arguments
714         //------------------------------------------------------------
715 
GetThisOffsetInternal.Runtime.CallConverter.ArgIterator716         public static int GetThisOffset()
717         {
718             return TransitionBlock.GetThisOffset();
719         }
720 
GetRetBuffArgOffsetInternal.Runtime.CallConverter.ArgIterator721         public unsafe int GetRetBuffArgOffset()
722         {
723             //            WRAPPER_NO_CONTRACT;
724 
725             Debug.Assert(this.HasRetBuffArg());
726 
727 #if _TARGET_X86_
728             // x86 is special as always
729             // DESKTOP BEHAVIOR            ret += this.HasThis() ? ArgumentRegisters.GetOffsetOfEdx() : ArgumentRegisters.GetOffsetOfEcx();
730             int ret = TransitionBlock.GetOffsetOfArgs();
731 #else
732             // RetBuf arg is in the first argument register by default
733             int ret = TransitionBlock.GetOffsetOfArgumentRegisters();
734 
735 #if _TARGET_ARM64_
736             ret += ArgumentRegisters.GetOffsetOfx8();
737 #else
738             // But if there is a this pointer, push it to the second.
739             if (this.HasThis())
740                 ret += IntPtr.Size;
741 #endif  // _TARGET_ARM64_
742 #endif  // _TARGET_X86_
743 
744             return ret;
745         }
746 
GetVASigCookieOffsetInternal.Runtime.CallConverter.ArgIterator747         unsafe public int GetVASigCookieOffset()
748         {
749             //            WRAPPER_NO_CONTRACT;
750 
751             Debug.Assert(this.IsVarArg());
752 
753 #if _TARGET_X86_
754             // x86 is special as always
755             return sizeof(TransitionBlock);
756 #else
757             // VaSig cookie is after this and retbuf arguments by default.
758             int ret = TransitionBlock.GetOffsetOfArgumentRegisters();
759 
760             if (this.HasThis())
761             {
762                 ret += IntPtr.Size;
763             }
764 
765             if (this.HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
766             {
767                 ret += IntPtr.Size;
768             }
769 
770             return ret;
771 #endif
772         }
773 
GetParamTypeArgOffsetInternal.Runtime.CallConverter.ArgIterator774         unsafe public int GetParamTypeArgOffset()
775         {
776             Debug.Assert(this.HasParamType());
777 
778 #if _TARGET_X86_
779             // x86 is special as always
780             if (!_SIZE_OF_ARG_STACK_COMPUTED)
781                 ForceSigWalk();
782 
783             switch (_paramTypeLoc)
784             {
785                 case ParamTypeLocation.Ecx:// PARAM_TYPE_REGISTER_ECX:
786                     return TransitionBlock.GetOffsetOfArgumentRegisters() + ArgumentRegisters.GetOffsetOfEcx();
787                 case ParamTypeLocation.Edx:
788                     return TransitionBlock.GetOffsetOfArgumentRegisters() + ArgumentRegisters.GetOffsetOfEdx();
789                 default:
790                     break;
791             }
792 
793             // The param type arg is last stack argument otherwise
794             return sizeof(TransitionBlock);
795 #else
796             // The hidden arg is after this and retbuf arguments by default.
797             int ret = TransitionBlock.GetOffsetOfArgumentRegisters();
798 
799             if (this.HasThis())
800             {
801                 ret += IntPtr.Size;
802             }
803 
804             if (this.HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
805             {
806                 ret += IntPtr.Size;
807             }
808 
809             return ret;
810 #endif
811         }
812 
813         //------------------------------------------------------------
814         // Each time this is called, this returns a byte offset of the next
815         // argument from the TransitionBlock* pointer. This offset can be positive *or* negative.
816         //
817         // Returns TransitionBlock::InvalidOffset once you've hit the end
818         // of the list.
819         //------------------------------------------------------------
GetNextOffsetInternal.Runtime.CallConverter.ArgIterator820         public unsafe int GetNextOffset()
821         {
822             //            WRAPPER_NO_CONTRACT;
823             //            SUPPORTS_DAC;
824 
825             if (!_ITERATION_STARTED)
826             {
827                 int numRegistersUsed = 0;
828 #if _TARGET_X86_
829                 int initialArgOffset = 0;
830 #endif
831                 if (this.HasThis())
832                     numRegistersUsed++;
833 
834                 if (this.HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
835                 {
836 #if !_TARGET_X86_
837                     numRegistersUsed++;
838 #else
839                     // DESKTOP BEHAVIOR is to do nothing here, as ret buf is never reached by the scan algortithm that walks backwards
840                     // but in .NET Native, the x86 argument scan is a forward scan, so we need to skip the ret buf arg (which is always
841                     // on the stack)
842                     initialArgOffset = IntPtr.Size;
843 #endif
844                 }
845 
846                 Debug.Assert(!this.IsVarArg() || !this.HasParamType());
847 
848                 // DESKTOP BEHAVIOR - This block is disabled for x86 as the param arg is the last argument on desktop x86.
849                 if (this.HasParamType())
850                 {
851                     numRegistersUsed++;
852                 }
853 
854 #if !_TARGET_X86_
855                 if (this.IsVarArg())
856                 {
857                     numRegistersUsed++;
858                 }
859 #endif
860 
861 #if _TARGET_X86_
862                 if (this.IsVarArg())
863                 {
864                     numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS; // Nothing else gets passed in registers for varargs
865                 }
866 
867 #if FEATURE_INTERPRETER
868                 switch (_interpreterCallingConvention)
869                 {
870                     case CallingConvention.StdCall:
871                         _numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS;
872                         _curOfs = TransitionBlock.GetOffsetOfArgs() + numRegistersUsed * IntPtr.Size + initialArgOffset;
873                         break;
874 
875                     case CallingConvention.ManagedStatic:
876                     case CallingConvention.ManagedInstance:
877                         _numRegistersUsed = numRegistersUsed;
878                         // DESKTOP BEHAVIOR     _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + SizeOfArgStack());
879                         _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + initialArgOffset);
880                         break;
881 
882                     default:
883                         Environment.FailFast("Unsupported calling convention.");
884                         break;
885                 }
886 #else
887                         _numRegistersUsed = numRegistersUsed;
888 // DESKTOP BEHAVIOR     _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + SizeOfArgStack());
889                         _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + initialArgOffset);
890 #endif
891 
892 #elif _TARGET_AMD64_
893 #if UNIX_AMD64_ABI
894                 _idxGenReg = numRegistersUsed;
895                 _idxStack = 0;
896                 _idxFPReg = 0;
897 #else
898                 _curOfs = TransitionBlock.GetOffsetOfArgs() + numRegistersUsed * IntPtr.Size;
899 #endif
900 #elif _TARGET_ARM_
901                 _idxGenReg = numRegistersUsed;
902                 _idxStack = 0;
903 
904                 _wFPRegs = 0;
905 #elif _TARGET_ARM64_
906                 _idxGenReg = numRegistersUsed;
907                 _idxStack = 0;
908 
909                 _idxFPReg = 0;
910 #elif _TARGET_WASM_
911                 throw new NotImplementedException();
912 #else
913                 PORTABILITY_ASSERT("ArgIterator::GetNextOffset");
914 #endif
915 
916 #if !_TARGET_WASM_
917                 _argNum = (_skipFirstArg ? 1 : 0);
918 
919                 _ITERATION_STARTED = true;
920 #endif // !_TARGET_WASM_
921             }
922 
923             if (_argNum >= this.NumFixedArgs())
924                 return TransitionBlock.InvalidOffset;
925 
926             CorElementType argType = this.GetArgumentType(_argNum, out _argTypeHandle, out _argForceByRef);
927 
928             _argTypeHandleOfByRefParam = (argType == CorElementType.ELEMENT_TYPE_BYREF ? _argData.GetByRefArgumentType(_argNum) : default(TypeHandle));
929 
930             _argNum++;
931 
932             int argSize = TypeHandle.GetElemSize(argType, _argTypeHandle);
933 
934 #if _TARGET_ARM64_
935             // NOT DESKTOP BEHAVIOR: The S and D registers overlap, and the UniversalTransitionThunk copies D registers to the transition blocks. We'll need
936             // to work with the D registers here as well.
937             if (argType == CorElementType.ELEMENT_TYPE_VALUETYPE && _argTypeHandle.IsHFA() && _argTypeHandle.GetHFAType() == CorElementType.ELEMENT_TYPE_R4)
938             {
939                 argSize *= 2;
940             }
941 #endif
942 
943             _argType = argType;
944             _argSize = argSize;
945 
946             argType = _argForceByRef ? CorElementType.ELEMENT_TYPE_BYREF : argType;
947             argSize = _argForceByRef ? IntPtr.Size : argSize;
948 
949 #pragma warning disable 219,168 // Unused local
950             int argOfs;
951 #pragma warning restore 219,168
952 
953 #if _TARGET_X86_
954 #if FEATURE_INTERPRETER
955             if (_interpreterCallingConvention != CallingConvention.ManagedStatic && _interpreterCallingConvention != CallingConvention.ManagedInstance)
956             {
957                 argOfs = _curOfs;
958                 _curOfs += ArchitectureConstants.StackElemSize(argSize);
959                 return argOfs;
960             }
961 #endif
962             if (IsArgumentInRegister(ref _numRegistersUsed, argType, _argTypeHandle))
963             {
964                 return TransitionBlock.GetOffsetOfArgumentRegisters() + (ArchitectureConstants.NUM_ARGUMENT_REGISTERS - _numRegistersUsed) * IntPtr.Size;
965             }
966 
967             // DESKTOP BEHAVIOR _curOfs -= ArchitectureConstants.StackElemSize(argSize);
968             // DESKTOP BEHAVIOR return _curOfs;
969             argOfs = _curOfs;
970             _curOfs += ArchitectureConstants.StackElemSize(argSize);
971             Debug.Assert(argOfs >= TransitionBlock.GetOffsetOfArgs());
972             return argOfs;
973 #elif _TARGET_AMD64_
974 #if UNIX_AMD64_ABI
975             int cFPRegs = 0;
976 
977             switch (argType)
978             {
979 
980                 case CorElementType.ELEMENT_TYPE_R4:
981                     // 32-bit floating point argument.
982                     cFPRegs = 1;
983                     break;
984 
985                 case CorElementType.ELEMENT_TYPE_R8:
986                     // 64-bit floating point argument.
987                     cFPRegs = 1;
988                     break;
989 
990                 case CorElementType.ELEMENT_TYPE_VALUETYPE:
991                     {
992                         // UNIXTODO: FEATURE_UNIX_AMD64_STRUCT_PASSING: Passing of structs, HFAs. For now, use the Windows convention.
993                         argSize = IntPtr.Size;
994                         break;
995                     }
996 
997                 default:
998                     break;
999             }
1000 
1001             int cbArg = ArchitectureConstants.StackElemSize(argSize);
1002             int cArgSlots = cbArg / ArchitectureConstants.STACK_ELEM_SIZE;
1003 
1004             if (cFPRegs > 0)
1005             {
1006                 if (cFPRegs + m_idxFPReg <= 8)
1007                 {
1008                     int argOfsInner = TransitionBlock.GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8;
1009                     m_idxFPReg += cFPRegs;
1010                     return argOfsInner;
1011                 }
1012             }
1013             else
1014             {
1015                 if (m_idxGenReg + cArgSlots <= 6)
1016                 {
1017                     int argOfsInner = TransitionBlock.GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
1018                     m_idxGenReg += cArgSlots;
1019                     return argOfsInner;
1020                 }
1021             }
1022 
1023             argOfs = TransitionBlock.GetOffsetOfArgs() + m_idxStack * 8;
1024             m_idxStack += cArgSlots;
1025             return argOfs;
1026 #else
1027             int cFPRegs = 0;
1028 
1029             switch (argType)
1030             {
1031                 case CorElementType.ELEMENT_TYPE_R4:
1032                     // 32-bit floating point argument.
1033                     cFPRegs = 1;
1034                     break;
1035 
1036                 case CorElementType.ELEMENT_TYPE_R8:
1037                     // 64-bit floating point argument.
1038                     cFPRegs = 1;
1039                     break;
1040             }
1041 
1042             // Each argument takes exactly one slot on AMD64
1043             argOfs = _curOfs - TransitionBlock.GetOffsetOfArgs();
1044             _curOfs += IntPtr.Size;
1045 
1046             if ((cFPRegs == 0) || (argOfs >= sizeof(ArgumentRegisters)))
1047             {
1048                 return argOfs + TransitionBlock.GetOffsetOfArgs();
1049             }
1050             else
1051             {
1052                 int idxFpReg = argOfs / IntPtr.Size;
1053                 return TransitionBlock.GetOffsetOfFloatArgumentRegisters() + idxFpReg * sizeof(M128A);
1054             }
1055 #endif
1056 #elif _TARGET_ARM_
1057             // First look at the underlying type of the argument to determine some basic properties:
1058             //  1) The size of the argument in bytes (rounded up to the stack slot size of 4 if necessary).
1059             //  2) Whether the argument represents a floating point primitive (ELEMENT_TYPE_R4 or ELEMENT_TYPE_R8).
1060             //  3) Whether the argument requires 64-bit alignment (anything that contains a Int64/UInt64).
1061 
1062             bool fFloatingPoint = false;
1063             bool fRequiresAlign64Bit = false;
1064 
1065             switch (argType)
1066             {
1067                 case CorElementType.ELEMENT_TYPE_I8:
1068                 case CorElementType.ELEMENT_TYPE_U8:
1069                     // 64-bit integers require 64-bit alignment on ARM.
1070                     fRequiresAlign64Bit = true;
1071                     break;
1072 
1073                 case CorElementType.ELEMENT_TYPE_R4:
1074                     // 32-bit floating point argument.
1075                     fFloatingPoint = true;
1076                     break;
1077 
1078                 case CorElementType.ELEMENT_TYPE_R8:
1079                     // 64-bit floating point argument.
1080                     fFloatingPoint = true;
1081                     fRequiresAlign64Bit = true;
1082                     break;
1083 
1084                 case CorElementType.ELEMENT_TYPE_VALUETYPE:
1085                     {
1086                         // Value type case: extract the alignment requirement, note that this has to handle
1087                         // the interop "native value types".
1088                         fRequiresAlign64Bit = _argTypeHandle.RequiresAlign8();
1089 
1090                         // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument
1091                         // registers if possible.
1092                         if (_argTypeHandle.IsHFA())
1093                             fFloatingPoint = true;
1094 
1095                         break;
1096                     }
1097 
1098                 default:
1099                     // The default is are 4-byte arguments (or promoted to 4 bytes), non-FP and don't require any
1100                     // 64-bit alignment.
1101                     break;
1102             }
1103 
1104             // Now attempt to place the argument into some combination of floating point or general registers and
1105             // the stack.
1106 
1107             // Save the alignment requirement
1108             _fRequires64BitAlignment = fRequiresAlign64Bit;
1109 
1110             int cbArg = ArchitectureConstants.StackElemSize(argSize);
1111             int cArgSlots = cbArg / 4;
1112 
1113             // Ignore floating point argument placement in registers if we're dealing with a vararg function (the ABI
1114             // specifies this so that vararg processing on the callee side is simplified).
1115             if (fFloatingPoint && !this.IsVarArg())
1116             {
1117                 // Handle floating point (primitive) arguments.
1118 
1119                 // First determine whether we can place the argument in VFP registers. There are 16 32-bit
1120                 // and 8 64-bit argument registers that share the same register space (e.g. D0 overlaps S0 and
1121                 // S1). The ABI specifies that VFP values will be passed in the lowest sequence of registers that
1122                 // haven't been used yet and have the required alignment. So the sequence (float, double, float)
1123                 // would be mapped to (S0, D1, S1) or (S0, S2/S3, S1).
1124                 //
1125                 // We use a 16-bit bitmap to record which registers have been used so far.
1126                 //
1127                 // So we can use the same basic loop for each argument type (float, double or HFA struct) we set up
1128                 // the following input parameters based on the size and alignment requirements of the arguments:
1129                 //   wAllocMask : bitmask of the number of 32-bit registers we need (1 for 1, 3 for 2, 7 for 3 etc.)
1130                 //   cSteps     : number of loop iterations it'll take to search the 16 registers
1131                 //   cShift     : how many bits to shift the allocation mask on each attempt
1132 
1133                 ushort wAllocMask = checked((ushort)((1 << (cbArg / 4)) - 1));
1134                 ushort cSteps = (ushort)(fRequiresAlign64Bit ? 9 - (cbArg / 8) : 17 - (cbArg / 4));
1135                 ushort cShift = fRequiresAlign64Bit ? (ushort)2 : (ushort)1;
1136 
1137                 // Look through the availability bitmask for a free register or register pair.
1138                 for (ushort i = 0; i < cSteps; i++)
1139                 {
1140                     if ((_wFPRegs & wAllocMask) == 0)
1141                     {
1142                         // We found one, mark the register or registers as used.
1143                         _wFPRegs |= wAllocMask;
1144 
1145                         // Indicate the registers used to the caller and return.
1146                         return TransitionBlock.GetOffsetOfFloatArgumentRegisters() + (i * cShift * 4);
1147                     }
1148                     wAllocMask <<= cShift;
1149                 }
1150 
1151                 // The FP argument is going to live on the stack. Once this happens the ABI demands we mark all FP
1152                 // registers as unavailable.
1153                 _wFPRegs = 0xffff;
1154 
1155                 // Doubles or HFAs containing doubles need the stack aligned appropriately.
1156                 if (fRequiresAlign64Bit)
1157                     _idxStack = ALIGN_UP(_idxStack, 2);
1158 
1159                 // Indicate the stack location of the argument to the caller.
1160                 int argOfsInner = TransitionBlock.GetOffsetOfArgs() + _idxStack * 4;
1161 
1162                 // Record the stack usage.
1163                 _idxStack += cArgSlots;
1164 
1165                 return argOfsInner;
1166             }
1167 
1168             //
1169             // Handle the non-floating point case.
1170             //
1171 
1172             if (_idxGenReg < 4)
1173             {
1174                 if (fRequiresAlign64Bit)
1175                 {
1176                     // The argument requires 64-bit alignment. Align either the next general argument register if
1177                     // we have any left.  See step C.3 in the algorithm in the ABI spec.
1178                     _idxGenReg = ALIGN_UP(_idxGenReg, 2);
1179                 }
1180 
1181                 int argOfsInner = TransitionBlock.GetOffsetOfArgumentRegisters() + _idxGenReg * 4;
1182 
1183                 int cRemainingRegs = 4 - _idxGenReg;
1184                 if (cArgSlots <= cRemainingRegs)
1185                 {
1186                     // Mark the registers just allocated as used.
1187                     _idxGenReg += cArgSlots;
1188                     return argOfsInner;
1189                 }
1190 
1191                 // The ABI supports splitting a non-FP argument across registers and the stack. But this is
1192                 // disabled if the FP arguments already overflowed onto the stack (i.e. the stack index is not
1193                 // zero). The following code marks the general argument registers as exhausted if this condition
1194                 // holds.  See steps C.5 in the algorithm in the ABI spec.
1195 
1196                 _idxGenReg = 4;
1197 
1198                 if (_idxStack == 0)
1199                 {
1200                     _idxStack += cArgSlots - cRemainingRegs;
1201                     return argOfsInner;
1202                 }
1203             }
1204 
1205             if (fRequiresAlign64Bit)
1206             {
1207                 // The argument requires 64-bit alignment. If it is going to be passed on the stack, align
1208                 // the next stack slot.  See step C.6 in the algorithm in the ABI spec.
1209                 _idxStack = ALIGN_UP(_idxStack, 2);
1210             }
1211 
1212             argOfs = TransitionBlock.GetOffsetOfArgs() + _idxStack * 4;
1213 
1214             // Advance the stack pointer over the argument just placed.
1215             _idxStack += cArgSlots;
1216 
1217             return argOfs;
1218 #elif _TARGET_ARM64_
1219 
1220             int cFPRegs = 0;
1221 
1222             switch (argType)
1223             {
1224                 case CorElementType.ELEMENT_TYPE_R4:
1225                     // 32-bit floating point argument.
1226                     cFPRegs = 1;
1227                     break;
1228 
1229                 case CorElementType.ELEMENT_TYPE_R8:
1230                     // 64-bit floating point argument.
1231                     cFPRegs = 1;
1232                     break;
1233 
1234                 case CorElementType.ELEMENT_TYPE_VALUETYPE:
1235                     {
1236                         // Handle HFAs: packed structures of 2-4 floats or doubles that are passed in FP argument
1237                         // registers if possible.
1238                         if (_argTypeHandle.IsHFA())
1239                         {
1240                             CorElementType type = _argTypeHandle.GetHFAType();
1241                             // DESKTOP BEHAVIOR cFPRegs = (type == CorElementType.ELEMENT_TYPE_R4) ? (argSize / sizeof(float)) : (argSize / sizeof(double));
1242                             cFPRegs = argSize / sizeof(double);
1243                         }
1244                         else
1245                         {
1246                             // Composite greater than 16bytes should be passed by reference
1247                             if (argSize > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE)
1248                             {
1249                                 argSize = IntPtr.Size;
1250                             }
1251                         }
1252 
1253                         break;
1254                     }
1255 
1256                 default:
1257                     break;
1258             }
1259 
1260             int cbArg = ArchitectureConstants.StackElemSize(argSize);
1261             int cArgSlots = cbArg / ArchitectureConstants.STACK_ELEM_SIZE;
1262 
1263             if (cFPRegs > 0 && !this.IsVarArg())
1264             {
1265                 if (cFPRegs + _idxFPReg <= 8)
1266                 {
1267                     int argOfsInner = TransitionBlock.GetOffsetOfFloatArgumentRegisters() + _idxFPReg * 8;
1268                     _idxFPReg += cFPRegs;
1269                     return argOfsInner;
1270                 }
1271                 else
1272                 {
1273                     _idxFPReg = 8;
1274                 }
1275             }
1276             else
1277             {
1278                 if (_idxGenReg + cArgSlots <= 8)
1279                 {
1280                     int argOfsInner = TransitionBlock.GetOffsetOfArgumentRegisters() + _idxGenReg * 8;
1281                     _idxGenReg += cArgSlots;
1282                     return argOfsInner;
1283                 }
1284                 else
1285                 {
1286                     _idxGenReg = 8;
1287                 }
1288             }
1289 
1290             argOfs = TransitionBlock.GetOffsetOfArgs() + _idxStack * 8;
1291             _idxStack += cArgSlots;
1292             return argOfs;
1293 #elif _TARGET_WASM_
1294             throw new NotImplementedException();
1295 #else
1296 #error            PORTABILITY_ASSERT("ArgIterator::GetNextOffset");
1297 #endif
1298         }
1299 
1300 
GetArgTypeInternal.Runtime.CallConverter.ArgIterator1301         public CorElementType GetArgType(out TypeHandle pTypeHandle)
1302         {
1303             //        LIMITED_METHOD_CONTRACT;
1304             pTypeHandle = _argTypeHandle;
1305             return _argType;
1306         }
1307 
GetByRefArgTypeInternal.Runtime.CallConverter.ArgIterator1308         public CorElementType GetByRefArgType(out TypeHandle pByRefArgTypeHandle)
1309         {
1310             //        LIMITED_METHOD_CONTRACT;
1311             pByRefArgTypeHandle = _argTypeHandleOfByRefParam;
1312             return _argType;
1313         }
1314 
GetArgSizeInternal.Runtime.CallConverter.ArgIterator1315         public int GetArgSize()
1316         {
1317             //        LIMITED_METHOD_CONTRACT;
1318             return _argSize;
1319         }
1320 
ForceSigWalkInternal.Runtime.CallConverter.ArgIterator1321         private unsafe void ForceSigWalk()
1322         {
1323             // This can be only used before the actual argument iteration started
1324             Debug.Assert(!_ITERATION_STARTED);
1325 
1326 #if _TARGET_X86_
1327             //
1328             // x86 is special as always
1329             //
1330 
1331             int numRegistersUsed = 0;
1332             int nSizeOfArgStack = 0;
1333 
1334             if (this.HasThis())
1335                 numRegistersUsed++;
1336 
1337             if (this.HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
1338             {
1339                 // DESKTOP BEHAVIOR                numRegistersUsed++;
1340                 // On ProjectN ret buff arg is passed on the call stack as the top stack arg
1341                 nSizeOfArgStack += IntPtr.Size;
1342             }
1343 
1344             // DESKTOP BEHAVIOR - This block is disabled for x86 as the param arg is the last argument on desktop x86.
1345             if (this.HasParamType())
1346             {
1347                 numRegistersUsed++;
1348                 _paramTypeLoc = (numRegistersUsed == 1) ?
1349                     ParamTypeLocation.Ecx : ParamTypeLocation.Edx;
1350                 Debug.Assert(numRegistersUsed <= 2);
1351             }
1352 
1353             if (this.IsVarArg())
1354             {
1355                 nSizeOfArgStack += IntPtr.Size;
1356                 numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS; // Nothing else gets passed in registers for varargs
1357             }
1358 
1359 #if FEATURE_INTERPRETER
1360             switch (_interpreterCallingConvention)
1361             {
1362                 case CallingConvention.StdCall:
1363                     numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS;
1364                     break;
1365 
1366                 case CallingConvention.ManagedStatic:
1367                 case CallingConvention.ManagedInstance:
1368                     break;
1369 
1370                 default:
1371                     Environment.FailFast("Unsupported calling convention.");
1372                     break;
1373             }
1374 #endif // FEATURE_INTERPRETER
1375 
1376             int nArgs = this.NumFixedArgs();
1377             for (int i = (_skipFirstArg ? 1 : 0); i < nArgs; i++)
1378             {
1379                 TypeHandle thArgType;
1380                 bool argForcedToBeByref;
1381                 CorElementType type = this.GetArgumentType(i, out thArgType, out argForcedToBeByref);
1382                 if (argForcedToBeByref)
1383                     type = CorElementType.ELEMENT_TYPE_BYREF;
1384 
1385                 if (!IsArgumentInRegister(ref numRegistersUsed, type, thArgType))
1386                 {
1387                     int structSize = TypeHandle.GetElemSize(type, thArgType);
1388 
1389                     nSizeOfArgStack += ArchitectureConstants.StackElemSize(structSize);
1390 
1391                     if (nSizeOfArgStack > ArchitectureConstants.MAX_ARG_SIZE)
1392                     {
1393                         throw new NotSupportedException();
1394                     }
1395                 }
1396             }
1397 
1398 #if DESKTOP            // DESKTOP BEHAVIOR
1399             if (this.HasParamType())
1400             {
1401                 if (numRegistersUsed < ArchitectureConstants.NUM_ARGUMENT_REGISTERS)
1402                 {
1403                     numRegistersUsed++;
1404                     paramTypeLoc = (numRegistersUsed == 1) ?
1405                         ParamTypeLocation.Ecx : ParamTypeLocation.Edx;
1406                 }
1407                 else
1408                 {
1409                     nSizeOfArgStack += IntPtr.Size;
1410                     paramTypeLoc = ParamTypeLocation.Stack;
1411                 }
1412             }
1413 #endif // DESKTOP BEHAVIOR
1414 
1415 #else // _TARGET_X86_
1416 
1417             int maxOffset = TransitionBlock.GetOffsetOfArgs();
1418 
1419             int ofs;
1420             while (TransitionBlock.InvalidOffset != (ofs = GetNextOffset()))
1421             {
1422                 int stackElemSize;
1423 
1424 #if _TARGET_AMD64_
1425                 // All stack arguments take just one stack slot on AMD64 because of arguments bigger
1426                 // than a stack slot are passed by reference.
1427                 stackElemSize = ArchitectureConstants.STACK_ELEM_SIZE;
1428 #else
1429                 stackElemSize = ArchitectureConstants.StackElemSize(GetArgSize());
1430                 if (IsArgPassedByRef())
1431                     stackElemSize = ArchitectureConstants.STACK_ELEM_SIZE;
1432 #endif
1433 
1434                 int endOfs = ofs + stackElemSize;
1435                 if (endOfs > maxOffset)
1436                 {
1437                     if (endOfs > ArchitectureConstants.MAX_ARG_SIZE)
1438                     {
1439                         throw new NotSupportedException();
1440                     }
1441                     maxOffset = endOfs;
1442                 }
1443             }
1444             // Clear the iterator started flag
1445             _ITERATION_STARTED = false;
1446 
1447             int nSizeOfArgStack = maxOffset - TransitionBlock.GetOffsetOfArgs();
1448 
1449 #if _TARGET_AMD64_ && !UNIX_AMD64_ABI
1450             nSizeOfArgStack = (nSizeOfArgStack > (int)sizeof(ArgumentRegisters)) ?
1451                 (nSizeOfArgStack - sizeof(ArgumentRegisters)) : 0;
1452 #endif
1453 
1454 #endif // _TARGET_X86_
1455 
1456             // Cache the result
1457             _nSizeOfArgStack = nSizeOfArgStack;
1458             _SIZE_OF_ARG_STACK_COMPUTED = true;
1459 
1460             this.Reset();
1461         }
1462 
1463 
1464 #if !_TARGET_X86_
1465         // Accessors for built in argument descriptions of the special implicit parameters not mentioned directly
1466         // in signatures (this pointer and the like). Whether or not these can be used successfully before all the
1467         // explicit arguments have been scanned is platform dependent.
GetThisLocInternal.Runtime.CallConverter.ArgIterator1468         public unsafe void GetThisLoc(ArgLocDesc* pLoc) { GetSimpleLoc(GetThisOffset(), pLoc); }
GetRetBuffArgLocInternal.Runtime.CallConverter.ArgIterator1469         public unsafe void GetRetBuffArgLoc(ArgLocDesc* pLoc) { GetSimpleLoc(GetRetBuffArgOffset(), pLoc); }
GetParamTypeLocInternal.Runtime.CallConverter.ArgIterator1470         public unsafe void GetParamTypeLoc(ArgLocDesc* pLoc) { GetSimpleLoc(GetParamTypeArgOffset(), pLoc); }
GetVASigCookieLocInternal.Runtime.CallConverter.ArgIterator1471         public unsafe void GetVASigCookieLoc(ArgLocDesc* pLoc) { GetSimpleLoc(GetVASigCookieOffset(), pLoc); }
1472 #endif // !_TARGET_X86_
1473 
1474 #if _TARGET_ARM_
1475         // Get layout information for the argument that the ArgIterator is currently visiting.
GetArgLocInternal.Runtime.CallConverter.ArgIterator1476         private unsafe void GetArgLoc(int argOffset, ArgLocDesc* pLoc)
1477         {
1478             //        LIMITED_METHOD_CONTRACT;
1479 
1480             pLoc->Init();
1481 
1482             pLoc->m_fRequires64BitAlignment = _fRequires64BitAlignment;
1483 
1484             int cSlots = (GetArgSize() + 3) / 4;
1485 
1486             if (TransitionBlock.IsFloatArgumentRegisterOffset(argOffset))
1487             {
1488                 pLoc->m_idxFloatReg = (argOffset - TransitionBlock.GetOffsetOfFloatArgumentRegisters()) / 4;
1489                 pLoc->m_cFloatReg = cSlots;
1490                 return;
1491             }
1492 
1493             if (!TransitionBlock.IsStackArgumentOffset(argOffset))
1494             {
1495                 pLoc->m_idxGenReg = TransitionBlock.GetArgumentIndexFromOffset(argOffset);
1496 
1497                 if (cSlots <= (4 - pLoc->m_idxGenReg))
1498                 {
1499                     pLoc->m_cGenReg = cSlots;
1500                 }
1501                 else
1502                 {
1503                     pLoc->m_cGenReg = 4 - pLoc->m_idxGenReg;
1504 
1505                     pLoc->m_idxStack = 0;
1506                     pLoc->m_cStack = cSlots - pLoc->m_cGenReg;
1507                 }
1508             }
1509             else
1510             {
1511                 pLoc->m_idxStack = TransitionBlock.GetArgumentIndexFromOffset(argOffset) - 4;
1512                 pLoc->m_cStack = cSlots;
1513             }
1514         }
1515 #endif // _TARGET_ARM_
1516 
1517 #if _TARGET_ARM64_
1518         // Get layout information for the argument that the ArgIterator is currently visiting.
GetArgLocInternal.Runtime.CallConverter.ArgIterator1519         private unsafe void GetArgLoc(int argOffset, ArgLocDesc* pLoc)
1520         {
1521             //        LIMITED_METHOD_CONTRACT;
1522 
1523             pLoc->Init();
1524 
1525             if (TransitionBlock.IsFloatArgumentRegisterOffset(argOffset))
1526             {
1527                 // Dividing by 8 as size of each register in FloatArgumentRegisters is 8 bytes.
1528                 pLoc->m_idxFloatReg = (argOffset - TransitionBlock.GetOffsetOfFloatArgumentRegisters()) / 8;
1529 
1530                 if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHFA())
1531                 {
1532                     CorElementType type = _argTypeHandle.GetHFAType();
1533                     bool isFloatType = (type == CorElementType.ELEMENT_TYPE_R4);
1534 
1535                     // DESKTOP BEHAVIOR pLoc->m_cFloatReg = isFloatType ? GetArgSize() / sizeof(float) : GetArgSize() / sizeof(double);
1536                     pLoc->m_cFloatReg = GetArgSize() / sizeof(double);
1537                     pLoc->m_isSinglePrecision = isFloatType;
1538                 }
1539                 else
1540                 {
1541                     pLoc->m_cFloatReg = 1;
1542                 }
1543                 return;
1544             }
1545 
1546             int cSlots = (GetArgSize() + 7) / 8;
1547 
1548             // Composites greater than 16bytes are passed by reference
1549             TypeHandle dummy;
1550             if (GetArgType(out dummy) == CorElementType.ELEMENT_TYPE_VALUETYPE && GetArgSize() > ArchitectureConstants.ENREGISTERED_PARAMTYPE_MAXSIZE)
1551             {
1552                 cSlots = 1;
1553             }
1554 
1555             if (!TransitionBlock.IsStackArgumentOffset(argOffset))
1556             {
1557                 pLoc->m_idxGenReg = TransitionBlock.GetArgumentIndexFromOffset(argOffset);
1558                 pLoc->m_cGenReg = cSlots;
1559             }
1560             else
1561             {
1562                 pLoc->m_idxStack = TransitionBlock.GetStackArgumentIndexFromOffset(argOffset);
1563                 pLoc->m_cStack = cSlots;
1564             }
1565         }
1566 #endif // _TARGET_ARM64_
1567 
1568 #if _TARGET_AMD64_ && UNIX_AMD64_ABI
1569         // Get layout information for the argument that the ArgIterator is currently visiting.
GetArgLocInternal.Runtime.CallConverter.ArgIterator1570         unsafe void GetArgLoc(int argOffset, ArgLocDesc* pLoc)
1571         {
1572             //        LIMITED_METHOD_CONTRACT;
1573 
1574             if (argOffset == TransitionBlock.StructInRegsOffset)
1575             {
1576                 // We always already have argLocDesc for structs passed in registers, we
1577                 // compute it in the GetNextOffset for those since it is always needed.
1578                 Debug.Assert(false);
1579                 return;
1580             }
1581 
1582             pLoc->Init();
1583 
1584             if (TransitionBlock.IsFloatArgumentRegisterOffset(argOffset))
1585             {
1586                 // Dividing by 8 as size of each register in FloatArgumentRegisters is 8 bytes.
1587                 pLoc->m_idxFloatReg = (argOffset - TransitionBlock.GetOffsetOfFloatArgumentRegisters()) / 8;
1588 
1589                 // UNIXTODO: Passing of structs, HFAs. For now, use the Windows convention.
1590                 pLoc->m_cFloatReg = 1;
1591                 return;
1592             }
1593 
1594             // UNIXTODO: Passing of structs, HFAs. For now, use the Windows convention.
1595             int cSlots = 1;
1596 
1597             if (!TransitionBlock.IsStackArgumentOffset(argOffset))
1598             {
1599                 pLoc->m_idxGenReg = TransitionBlock.GetArgumentIndexFromOffset(argOffset);
1600                 pLoc->m_cGenReg = cSlots;
1601             }
1602             else
1603             {
1604                 pLoc->m_idxStack = (argOffset - TransitionBlock.GetOffsetOfArgs()) / 8;
1605                 pLoc->m_cStack = cSlots;
1606             }
1607         }
1608 #endif // _TARGET_AMD64_ && UNIX_AMD64_ABI
1609 
1610         private int _nSizeOfArgStack;      // Cached value of SizeOfArgStack
1611 
1612         private int _argNum;
1613 
1614         // Cached information about last argument
1615         private CorElementType _argType;
1616         private int _argSize;
1617         private TypeHandle _argTypeHandle;
1618         private TypeHandle _argTypeHandleOfByRefParam;
1619         private bool _argForceByRef;
1620 
1621 #if _TARGET_X86_
1622         private int _curOfs;           // Current position of the stack iterator
1623         private int _numRegistersUsed;
1624 #endif
1625 
1626 #if _TARGET_AMD64_
1627 #if UNIX_AMD64_ABI
1628         int _idxGenReg;
1629         int _idxStack;
1630         int _idxFPReg;
1631 #else
1632         private int _curOfs;           // Current position of the stack iterator
1633 #endif
1634 #endif
1635 
1636 #if _TARGET_ARM_
1637         private int _idxGenReg;        // Next general register to be assigned a value
1638         private int _idxStack;         // Next stack slot to be assigned a value
1639 
1640         private ushort _wFPRegs;          // Bitmask of available floating point argument registers (s0-s15/d0-d7)
1641         private bool _fRequires64BitAlignment; // Cached info about the current arg
1642 #endif
1643 
1644 #if _TARGET_ARM64_
1645         private int _idxGenReg;        // Next general register to be assigned a value
1646         private int _idxStack;         // Next stack slot to be assigned a value
1647         private int _idxFPReg;         // Next FP register to be assigned a value
1648 #endif
1649 
1650         // These are enum flags in CallingConvention.h, but that's really ugly in C#, so I've changed them to bools.
1651         private bool _ITERATION_STARTED; // Started iterating over arguments
1652         private bool _SIZE_OF_ARG_STACK_COMPUTED;
1653         private bool _RETURN_FLAGS_COMPUTED;
1654         private bool _RETURN_HAS_RET_BUFFER; // Cached value of HasRetBuffArg
1655         private uint _fpReturnSize;
1656 
1657         //        enum {
1658         /*        ITERATION_STARTED               = 0x0001,
1659                 SIZE_OF_ARG_STACK_COMPUTED      = 0x0002,
1660                 RETURN_FLAGS_COMPUTED           = 0x0004,
1661                 RETURN_HAS_RET_BUFFER           = 0x0008,   // Cached value of HasRetBuffArg
1662         */
1663 #if _TARGET_X86_
1664         private enum ParamTypeLocation
1665         {
1666             Stack,
1667             Ecx,
1668             Edx
1669         }
1670         private ParamTypeLocation _paramTypeLoc;
1671         /*        PARAM_TYPE_REGISTER_MASK        = 0x0030,
1672                 PARAM_TYPE_REGISTER_STACK       = 0x0010,
1673                 PARAM_TYPE_REGISTER_ECX         = 0x0020,
1674                 PARAM_TYPE_REGISTER_EDX         = 0x0030,*/
1675 #endif
1676 
1677         //        METHOD_INVOKE_NEEDS_ACTIVATION  = 0x0040,   // Flag used by ArgIteratorForMethodInvoke
1678 
1679         //        RETURN_FP_SIZE_SHIFT            = 8,        // The rest of the flags is cached value of GetFPReturnSize
1680         //    };
1681 
ComputeReturnValueTreatmentInternal.Runtime.CallConverter.ArgIterator1682         internal static void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetType, bool isVarArgMethod, out bool usesRetBuffer, out uint fpReturnSize)
1683 
1684         {
1685             usesRetBuffer = false;
1686             fpReturnSize = 0;
1687 
1688             switch (type)
1689             {
1690                 case CorElementType.ELEMENT_TYPE_TYPEDBYREF:
1691                     throw new NotSupportedException();
1692 #if ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
1693                     //                    if (sizeof(TypedByRef) > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE)
1694                     //                        flags |= RETURN_HAS_RET_BUFFER;
1695 #else
1696 //                    flags |= RETURN_HAS_RET_BUFFER;
1697 #endif
1698                 //                    break;
1699 
1700                 case CorElementType.ELEMENT_TYPE_R4:
1701                     fpReturnSize = sizeof(float);
1702                     break;
1703 
1704                 case CorElementType.ELEMENT_TYPE_R8:
1705                     fpReturnSize = sizeof(double);
1706                     break;
1707 
1708                 case CorElementType.ELEMENT_TYPE_VALUETYPE:
1709 #if ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
1710                     {
1711                         Debug.Assert(!thRetType.IsNull() && thRetType.IsValueType());
1712 
1713 #if FEATURE_HFA
1714                         if (thRetType.IsHFA() && !isVarArgMethod)
1715                         {
1716                             CorElementType hfaType = thRetType.GetHFAType();
1717 
1718 #if _TARGET_ARM64_
1719                             // DESKTOP BEHAVIOR fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ? (4 * (uint)sizeof(float)) : (4 * (uint)sizeof(double));
1720                             // S and D registers overlap. Since we copy D registers in the UniversalTransitionThunk, we'll
1721                             // thread floats like doubles during copying.
1722                             fpReturnSize = 4 * (uint)sizeof(double);
1723 #else
1724                             fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ?
1725                                 (4 * (uint)sizeof(float)) :
1726                                 (4 * (uint)sizeof(double));
1727 #endif
1728 
1729                             break;
1730                         }
1731 #endif
1732 
1733                         uint size = thRetType.GetSize();
1734 
1735 #if _TARGET_X86_ || _TARGET_AMD64_
1736                         // Return value types of size which are not powers of 2 using a RetBuffArg
1737                         if ((size & (size - 1)) != 0)
1738                         {
1739                             usesRetBuffer = true;
1740                             break;
1741                         }
1742 #endif
1743 
1744                         if (size <= ArchitectureConstants.ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE)
1745                             break;
1746                     }
1747 #endif // ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
1748 
1749                     // Value types are returned using return buffer by default
1750                     usesRetBuffer = true;
1751                     break;
1752 
1753                 default:
1754                     break;
1755             }
1756         }
1757 
ComputeReturnFlagsInternal.Runtime.CallConverter.ArgIterator1758         private void ComputeReturnFlags()
1759         {
1760             TypeHandle thRetType;
1761             CorElementType type = this.GetReturnType(out thRetType, out _RETURN_HAS_RET_BUFFER);
1762 
1763             if (!_RETURN_HAS_RET_BUFFER)
1764             {
1765                 ComputeReturnValueTreatment(type, thRetType, this.IsVarArg(), out _RETURN_HAS_RET_BUFFER, out _fpReturnSize);
1766             }
1767 
1768             _RETURN_FLAGS_COMPUTED = true;
1769         }
1770 
1771 
1772 #if !_TARGET_X86_
GetSimpleLocInternal.Runtime.CallConverter.ArgIterator1773         private unsafe void GetSimpleLoc(int offset, ArgLocDesc* pLoc)
1774         {
1775             //        WRAPPER_NO_CONTRACT;
1776             pLoc->Init();
1777             pLoc->m_idxGenReg = TransitionBlock.GetArgumentIndexFromOffset(offset);
1778             pLoc->m_cGenReg = 1;
1779         }
1780 #endif
1781 
ALIGN_UPInternal.Runtime.CallConverter.ArgIterator1782         public static int ALIGN_UP(int input, int align_to)
1783         {
1784             return (input + (align_to - 1)) & ~(align_to - 1);
1785         }
1786 
IS_ALIGNEDInternal.Runtime.CallConverter.ArgIterator1787         public static bool IS_ALIGNED(IntPtr val, int alignment)
1788         {
1789             Debug.Assert(0 == (alignment & (alignment - 1)));
1790             return 0 == (val.ToInt64() & (alignment - 1));
1791         }
1792 
IsRetBuffPassedAsFirstArgInternal.Runtime.CallConverter.ArgIterator1793         public static bool IsRetBuffPassedAsFirstArg()
1794         {
1795             //        WRAPPER_NO_CONTRACT;
1796 #if !_TARGET_ARM64_
1797             return true;
1798 #else
1799             return false;
1800 #endif
1801         }
1802     };
1803 }
1804