in src/coreclr/vm/callingconvention.h [1131:1912]
int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
if (!(m_dwFlags & ITERATION_STARTED))
{
int numRegistersUsed = 0;
if (this->HasThis())
numRegistersUsed++;
if (this->HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
numRegistersUsed++;
_ASSERTE(!this->IsVarArg() || !this->HasParamType());
#ifndef TARGET_X86
if (this->IsVarArg() || this->HasParamType())
{
numRegistersUsed++;
}
#endif
#ifdef TARGET_X86
if (this->IsVarArg())
{
numRegistersUsed = NUM_ARGUMENT_REGISTERS; // Nothing else gets passed in registers for varargs
}
#ifdef FEATURE_INTERPRETER
BYTE callconv = CallConv();
switch (callconv)
{
case IMAGE_CEE_CS_CALLCONV_C:
case IMAGE_CEE_CS_CALLCONV_STDCALL:
m_numRegistersUsed = NUM_ARGUMENT_REGISTERS;
m_ofsStack = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
m_fUnmanagedCallConv = true;
break;
case IMAGE_CEE_CS_CALLCONV_THISCALL:
case IMAGE_CEE_CS_CALLCONV_FASTCALL:
_ASSERTE_MSG(false, "Unsupported calling convention.");
default:
m_fUnmanagedCallConv = false;
m_numRegistersUsed = numRegistersUsed;
m_ofsStack = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
break;
}
#else
m_numRegistersUsed = numRegistersUsed;
m_ofsStack = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
#endif
#elif defined(TARGET_AMD64)
#ifdef UNIX_AMD64_ABI
m_idxGenReg = numRegistersUsed;
m_ofsStack = 0;
m_idxFPReg = 0;
#else
m_ofsStack = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
#endif
#elif defined(TARGET_ARM)
m_idxGenReg = numRegistersUsed;
m_ofsStack = 0;
m_wFPRegs = 0;
#elif defined(TARGET_ARM64)
m_idxGenReg = numRegistersUsed;
m_ofsStack = 0;
m_idxFPReg = 0;
#elif defined(TARGET_LOONGARCH64)
m_idxGenReg = numRegistersUsed;
m_ofsStack = 0;
m_idxFPReg = 0;
#elif defined(TARGET_RISCV64)
m_idxGenReg = numRegistersUsed;
m_ofsStack = 0;
m_idxFPReg = 0;
#else
PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
#endif
m_argNum = 0;
m_dwFlags |= ITERATION_STARTED;
}
// We're done going through the args for this MetaSig
if (m_argNum == this->NumFixedArgs())
return TransitionBlock::InvalidOffset;
TypeHandle thValueType;
CorElementType argType = this->GetNextArgumentType(m_argNum++, &thValueType);
// TypedReference behaves like a valuetype
if (argType == ELEMENT_TYPE_TYPEDBYREF)
{
argType = ELEMENT_TYPE_VALUETYPE;
thValueType = TypeHandle(g_TypedReferenceMT);
}
int argSize = MetaSig::GetElemSize(argType, thValueType);
m_argType = argType;
m_argSize = argSize;
m_argTypeHandle = thValueType;
#if defined(UNIX_AMD64_ABI) || defined (TARGET_ARM64) || defined (TARGET_LOONGARCH64) || defined (TARGET_RISCV64)
m_hasArgLocDescForStructInRegs = false;
#endif
#ifdef TARGET_X86
#ifdef FEATURE_INTERPRETER
if (m_fUnmanagedCallConv)
{
int argOfs = m_ofsStack;
m_ofsStack += StackElemSize(argSize);
return argOfs;
}
#endif
if (IsArgumentInRegister(&m_numRegistersUsed, argType, thValueType))
{
return TransitionBlock::GetOffsetOfArgumentRegisters() + (NUM_ARGUMENT_REGISTERS - m_numRegistersUsed) * sizeof(void *);
}
m_ofsStack -= StackElemSize(argSize);
_ASSERTE(m_ofsStack >= TransitionBlock::GetOffsetOfArgs());
return m_ofsStack;
#elif defined(TARGET_AMD64)
#ifdef UNIX_AMD64_ABI
m_fArgInRegisters = true;
int cFPRegs = 0;
int cGenRegs = 0;
int cbArg = StackElemSize(argSize);
switch (argType)
{
case ELEMENT_TYPE_R4:
// 32-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_R8:
// 64-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_VALUETYPE:
{
MethodTable *pMT = m_argTypeHandle.GetMethodTable();
if (this->IsRegPassedStruct(pMT))
{
EEClass* eeClass = pMT->GetClass();
cGenRegs = 0;
for (int i = 0; i < eeClass->GetNumberEightBytes(); i++)
{
switch (eeClass->GetEightByteClassification(i))
{
case SystemVClassificationTypeInteger:
case SystemVClassificationTypeIntegerReference:
case SystemVClassificationTypeIntegerByRef:
cGenRegs++;
break;
case SystemVClassificationTypeSSE:
cFPRegs++;
break;
default:
_ASSERTE(false);
break;
}
}
// Check if we have enough registers available for the struct passing
if ((cFPRegs + m_idxFPReg <= NUM_FLOAT_ARGUMENT_REGISTERS) && (cGenRegs + m_idxGenReg) <= NUM_ARGUMENT_REGISTERS)
{
m_argLocDescForStructInRegs.Init();
m_argLocDescForStructInRegs.m_cGenReg = cGenRegs;
m_argLocDescForStructInRegs.m_cFloatReg = cFPRegs;
m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg;
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
m_argLocDescForStructInRegs.m_eeClass = eeClass;
m_hasArgLocDescForStructInRegs = true;
m_idxGenReg += cGenRegs;
m_idxFPReg += cFPRegs;
return TransitionBlock::StructInRegsOffset;
}
}
// Set the register counts to indicate that this argument will not be passed in registers
cFPRegs = 0;
cGenRegs = 0;
break;
}
default:
cGenRegs = cbArg / 8; // GP reg size
break;
}
if ((cFPRegs > 0) && (cFPRegs + m_idxFPReg <= NUM_FLOAT_ARGUMENT_REGISTERS))
{
int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 16;
m_idxFPReg += cFPRegs;
return argOfs;
}
else if ((cGenRegs > 0) && (m_idxGenReg + cGenRegs <= NUM_ARGUMENT_REGISTERS))
{
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_idxGenReg += cGenRegs;
return argOfs;
}
m_fArgInRegisters = false;
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
m_ofsStack += cbArg;
return argOfs;
#else
// Each argument takes exactly one slot on AMD64 on Windows
int argOfs = m_ofsStack;
m_ofsStack += sizeof(void *);
return argOfs;
#endif
#elif defined(TARGET_ARM)
// First look at the underlying type of the argument to determine some basic properties:
// 1) The size of the argument in bytes (rounded up to the stack slot size of 4 if necessary).
// 2) Whether the argument represents a floating point primitive (ELEMENT_TYPE_R4 or ELEMENT_TYPE_R8).
// 3) Whether the argument requires 64-bit alignment (anything that contains a Int64/UInt64).
bool fFloatingPoint = false;
bool fRequiresAlign64Bit = false;
switch (argType)
{
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
// 64-bit integers require 64-bit alignment on ARM.
fRequiresAlign64Bit = true;
break;
case ELEMENT_TYPE_R4:
// 32-bit floating point argument.
fFloatingPoint = true;
break;
case ELEMENT_TYPE_R8:
// 64-bit floating point argument.
fFloatingPoint = true;
fRequiresAlign64Bit = true;
break;
case ELEMENT_TYPE_VALUETYPE:
{
// Value type case: extract the alignment requirement, note that this has to handle
// the interop "native value types".
fRequiresAlign64Bit = thValueType.RequiresAlign8();
#ifdef FEATURE_HFA
// Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument
// registers if possible.
if (thValueType.IsHFA())
{
fFloatingPoint = true;
}
#endif
break;
}
default:
// The default is are 4-byte arguments (or promoted to 4 bytes), non-FP and don't require any
// 64-bit alignment.
break;
}
// Now attempt to place the argument into some combination of floating point or general registers and
// the stack.
// Save the alignment requirement
m_fRequires64BitAlignment = fRequiresAlign64Bit;
int cbArg = StackElemSize(argSize);
_ASSERTE((cbArg % TARGET_POINTER_SIZE) == 0);
// Ignore floating point argument placement in registers if we're dealing with a vararg function (the ABI
// specifies this so that vararg processing on the callee side is simplified).
#ifndef ARM_SOFTFP
if (fFloatingPoint && !this->IsVarArg())
{
// Handle floating point (primitive) arguments.
// First determine whether we can place the argument in VFP registers. There are 16 32-bit
// and 8 64-bit argument registers that share the same register space (e.g. D0 overlaps S0 and
// S1). The ABI specifies that VFP values will be passed in the lowest sequence of registers that
// haven't been used yet and have the required alignment. So the sequence (float, double, float)
// would be mapped to (S0, D1, S1) or (S0, S2/S3, S1).
//
// We use a 16-bit bitmap to record which registers have been used so far.
//
// So we can use the same basic loop for each argument type (float, double or HFA struct) we set up
// the following input parameters based on the size and alignment requirements of the arguments:
// wAllocMask : bitmask of the number of 32-bit registers we need (1 for 1, 3 for 2, 7 for 3 etc.)
// cSteps : number of loop iterations it'll take to search the 16 registers
// cShift : how many bits to shift the allocation mask on each attempt
WORD wAllocMask = (1 << (cbArg / 4)) - 1;
WORD cSteps = (WORD)(fRequiresAlign64Bit ? 9 - (cbArg / 8) : 17 - (cbArg / 4));
WORD cShift = fRequiresAlign64Bit ? 2 : 1;
// Look through the availability bitmask for a free register or register pair.
for (WORD i = 0; i < cSteps; i++)
{
if ((m_wFPRegs & wAllocMask) == 0)
{
// We found one, mark the register or registers as used.
m_wFPRegs |= wAllocMask;
// Indicate the registers used to the caller and return.
return TransitionBlock::GetOffsetOfFloatArgumentRegisters() + (i * cShift * 4);
}
wAllocMask <<= cShift;
}
// The FP argument is going to live on the stack. Once this happens the ABI demands we mark all FP
// registers as unavailable.
m_wFPRegs = 0xffff;
// Doubles or HFAs containing doubles need the stack aligned appropriately.
if (fRequiresAlign64Bit)
{
m_ofsStack = (int)ALIGN_UP(m_ofsStack, TARGET_POINTER_SIZE * 2);
}
// Indicate the stack location of the argument to the caller.
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
// Record the stack usage.
m_ofsStack += cbArg;
return argOfs;
}
#endif // ARM_SOFTFP
//
// Handle the non-floating point case.
//
if (m_idxGenReg < 4)
{
if (fRequiresAlign64Bit)
{
// The argument requires 64-bit alignment. Align either the next general argument register if
// we have any left. See step C.3 in the algorithm in the ABI spec.
m_idxGenReg = (int)ALIGN_UP(m_idxGenReg, 2);
}
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 4;
int cRemainingRegs = 4 - m_idxGenReg;
if (cbArg <= cRemainingRegs * TARGET_POINTER_SIZE)
{
// Mark the registers just allocated as used.
m_idxGenReg += ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
return argOfs;
}
// The ABI supports splitting a non-FP argument across registers and the stack. But this is
// disabled if the FP arguments already overflowed onto the stack (i.e. the stack index is not
// zero). The following code marks the general argument registers as exhausted if this condition
// holds. See steps C.5 in the algorithm in the ABI spec.
m_idxGenReg = 4;
if (m_ofsStack == 0)
{
m_ofsStack += cbArg - cRemainingRegs * TARGET_POINTER_SIZE;
return argOfs;
}
}
if (fRequiresAlign64Bit)
{
// The argument requires 64-bit alignment. If it is going to be passed on the stack, align
// the next stack slot. See step C.6 in the algorithm in the ABI spec.
m_ofsStack = (int)ALIGN_UP(m_ofsStack, TARGET_POINTER_SIZE * 2);
}
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
// Advance the stack pointer over the argument just placed.
m_ofsStack += cbArg;
return argOfs;
#elif defined(TARGET_ARM64)
int cFPRegs = 0;
switch (argType)
{
case ELEMENT_TYPE_R4:
// 32-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_R8:
// 64-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_VALUETYPE:
{
// Handle HFAs: packed structures of 1-4 floats, doubles, or short vectors
// that are passed in FP argument registers if possible.
if (thValueType.IsHFA())
{
CorInfoHFAElemType type = thValueType.GetHFAType();
m_argLocDescForStructInRegs.Init();
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
m_argLocDescForStructInRegs.setHFAFieldSize(type);
cFPRegs = argSize/m_argLocDescForStructInRegs.m_hfaFieldSize;
m_argLocDescForStructInRegs.m_cFloatReg = cFPRegs;
// Check if we have enough registers available for the HFA passing
if ((cFPRegs + m_idxFPReg) <= 8)
{
m_hasArgLocDescForStructInRegs = true;
}
}
else
{
// Composite greater than 16bytes should be passed by reference
if (argSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
{
argSize = sizeof(TADDR);
}
}
break;
}
default:
break;
}
const bool isValueType = (argType == ELEMENT_TYPE_VALUETYPE);
const bool isFloatHfa = thValueType.IsFloatHfa();
const int cbArg = StackElemSize(argSize, isValueType, isFloatHfa);
if (cFPRegs>0 && !this->IsVarArg())
{
if (cFPRegs + m_idxFPReg <= 8)
{
// Each floating point register in the argument area is 16 bytes.
int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 16;
m_idxFPReg += cFPRegs;
return argOfs;
}
else
{
m_idxFPReg = 8;
}
}
else
{
#if !defined(OSX_ARM64_ABI)
_ASSERTE((cbArg% TARGET_POINTER_SIZE) == 0);
#endif
const int regSlots = ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
// Only x0-x7 are valid argument registers (x8 is always the return buffer)
if (m_idxGenReg + regSlots <= 8)
{
// The entirety of the arg fits in the register slots.
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_idxGenReg += regSlots;
return argOfs;
}
else
{
#ifdef _WIN32
if (this->IsVarArg() && m_idxGenReg < 8)
{
// Address the Windows ARM64 varargs case where an arg is split between regs and stack.
// This can happen in the varargs case because the first 64 bytes of the stack are loaded
// into x0-x7, and any remaining stack arguments are placed normally.
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
// Increase m_ofsStack to account for the space used for the remainder of the arg after
// registers are filled.
m_ofsStack += cbArg + (m_idxGenReg - 8) * TARGET_POINTER_SIZE;
// We used up the remaining reg slots.
m_idxGenReg = 8;
return argOfs;
}
else
#endif
{
// Don't use reg slots for this. It will be passed purely on the stack arg space.
m_idxGenReg = 8;
}
}
}
#ifdef OSX_ARM64_ABI
int alignment;
if (!isValueType)
{
_ASSERTE((cbArg & (cbArg - 1)) == 0);
alignment = cbArg;
}
else if (isFloatHfa)
{
alignment = 4;
}
else
{
alignment = 8;
}
m_ofsStack = (int)ALIGN_UP(m_ofsStack, alignment);
#endif // OSX_ARM64_ABI
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
m_ofsStack += cbArg;
return argOfs;
#elif defined(TARGET_LOONGARCH64)
int cFPRegs = 0;
int flags = 0;
switch (argType)
{
case ELEMENT_TYPE_R4:
// 32-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_R8:
// 64-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_VALUETYPE:
{
// Handle struct which containing floats or doubles that can be passed
// in FP registers if possible.
// Composite greater than 16bytes should be passed by reference
if (argSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
{
argSize = sizeof(TADDR);
}
else
{
flags = MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType);
if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)
{
cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1;
}
}
break;
}
default:
break;
}
const bool isValueType = (argType == ELEMENT_TYPE_VALUETYPE);
const bool isFloatHfa = thValueType.IsFloatHfa();
const int cbArg = StackElemSize(argSize, isValueType, isFloatHfa);
if (cFPRegs > 0 && !this->IsVarArg())
{
if (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND))
{
assert(cFPRegs == 1);
assert((STRUCT_FLOAT_FIELD_FIRST == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)) || (STRUCT_FLOAT_FIELD_SECOND == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)));
if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (m_idxGenReg + 1 <= NUM_ARGUMENT_REGISTERS))
{
int argOfs = 0;
m_argLocDescForStructInRegs.Init();
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
m_argLocDescForStructInRegs.m_cFloatReg = 1;
m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg;
m_argLocDescForStructInRegs.m_cGenReg = 1;
m_argLocDescForStructInRegs.m_structFields = flags;
if (flags & STRUCT_FLOAT_FIELD_SECOND)
{
argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
}
else
{
argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8;
}
m_idxFPReg += 1;
m_idxGenReg += 1;
m_hasArgLocDescForStructInRegs = true;
return argOfs;
}
}
else if (cFPRegs + m_idxFPReg <= NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8;
if (flags == STRUCT_FLOAT_FIELD_ONLY_TWO) // struct with two float-fields.
{
m_argLocDescForStructInRegs.Init();
m_hasArgLocDescForStructInRegs = true;
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
assert(cFPRegs == 2);
m_argLocDescForStructInRegs.m_cFloatReg = 2;
assert(argSize == 8);
m_argLocDescForStructInRegs.m_structFields = STRUCT_FLOAT_FIELD_ONLY_TWO;
}
m_idxFPReg += cFPRegs;
return argOfs;
}
}
{
const int regSlots = ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
if (m_idxGenReg + regSlots <= NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_idxGenReg += regSlots;
return argOfs;
}
else if (m_idxGenReg < NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_ofsStack += (m_idxGenReg + regSlots - NUM_ARGUMENT_REGISTERS)*8;
assert(m_ofsStack == 8);
m_idxGenReg = NUM_ARGUMENT_REGISTERS;
return argOfs;
}
}
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
m_ofsStack += ALIGN_UP(cbArg, TARGET_POINTER_SIZE);
return argOfs;
#elif defined(TARGET_RISCV64)
int cFPRegs = 0;
int flags = 0;
switch (argType)
{
case ELEMENT_TYPE_R4:
// 32-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_R8:
// 64-bit floating point argument.
cFPRegs = 1;
break;
case ELEMENT_TYPE_VALUETYPE:
{
// Handle struct which containing floats or doubles that can be passed
// in FP registers if possible.
// Composite greater than 16bytes should be passed by reference
if (argSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
{
argSize = sizeof(TADDR);
}
else
{
flags = MethodTable::GetRiscV64PassStructInRegisterFlags(thValueType);
if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)
{
cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1;
}
}
break;
}
default:
break;
}
const bool isValueType = (argType == ELEMENT_TYPE_VALUETYPE);
const bool isFloatHfa = thValueType.IsFloatHfa();
const int cbArg = StackElemSize(argSize, isValueType, isFloatHfa);
if (cFPRegs > 0 && !this->IsVarArg())
{
if (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND))
{
assert(cFPRegs == 1);
assert((STRUCT_FLOAT_FIELD_FIRST == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)) || (STRUCT_FLOAT_FIELD_SECOND == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)));
if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (m_idxGenReg + 1 <= NUM_ARGUMENT_REGISTERS))
{
m_argLocDescForStructInRegs.Init();
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
m_argLocDescForStructInRegs.m_cFloatReg = 1;
int argOfs = (flags & STRUCT_FLOAT_FIELD_SECOND)
? TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8
: TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8;
m_idxFPReg += 1;
m_argLocDescForStructInRegs.m_structFields = flags;
m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg;
m_argLocDescForStructInRegs.m_cGenReg = 1;
m_idxGenReg += 1;
m_hasArgLocDescForStructInRegs = true;
return argOfs;
}
}
else if (cFPRegs + m_idxFPReg <= NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8;
if (flags == STRUCT_FLOAT_FIELD_ONLY_TWO) // struct with two float-fields.
{
m_argLocDescForStructInRegs.Init();
m_hasArgLocDescForStructInRegs = true;
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
assert(cFPRegs == 2);
m_argLocDescForStructInRegs.m_cFloatReg = 2;
assert(argSize == 8);
m_argLocDescForStructInRegs.m_structFields = STRUCT_FLOAT_FIELD_ONLY_TWO;
}
m_idxFPReg += cFPRegs;
return argOfs;
}
}
{
const int regSlots = ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
if (m_idxGenReg + regSlots <= NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_idxGenReg += regSlots;
return argOfs;
}
else if (m_idxGenReg < NUM_ARGUMENT_REGISTERS)
{
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
m_ofsStack += (m_idxGenReg + regSlots - NUM_ARGUMENT_REGISTERS)*8;
assert(m_ofsStack == 8);
m_idxGenReg = NUM_ARGUMENT_REGISTERS;
return argOfs;
}
}
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
m_ofsStack += ALIGN_UP(cbArg, TARGET_POINTER_SIZE);
return argOfs;
#else
PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
return TransitionBlock::InvalidOffset;
#endif
}