Repository: dotnet/runtime
File: src/coreclr/vm/callingconvention.h (C/C++)

Code before:
            assert(m_idxGenReg == lastReg); // pass head in last register
            assert(m_ofsStack == 0); // pass tail in first stack slot

            int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + lastReg * TARGET_POINTER_SIZE;
            m_idxGenReg = NUM_ARGUMENT_REGISTERS;
            m_ofsStack = TARGET_POINTER_SIZE;
            return argOfs;
        }
    }

    // Pass argument entirely on stack
    int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
    m_ofsStack += ALIGN_UP(cbArg, TARGET_POINTER_SIZE);

    return argOfs;
#elif defined(TARGET_WASM)

    size_t align;
    if (argType == ELEMENT_TYPE_VALUETYPE && argSize > INTERP_STACK_SLOT_SIZE)
    {
        align = CEEInfo::getClassAlignmentRequirementStatic(thValueType.GetMethodTable());
        if (align < INTERP_STACK_SLOT_SIZE)
            align = INTERP_STACK_SLOT_SIZE;

        if (align > INTERP_STACK_ALIGNMENT)
            align = INTERP_STACK_ALIGNMENT;
    } else {
        align = INTERP_STACK_SLOT_SIZE;
    }

    m_ofsStack = ALIGN_UP(m_ofsStack, align);

    int cbArg = ALIGN_UP(argSize, INTERP_STACK_SLOT_SIZE);
    int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;

    m_ofsStack += cbArg;

    return argOfs;
#else
    PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
    return TransitionBlock::InvalidOffset;
#endif
}

template<class ARGITERATOR_BASE>
void ArgIteratorTemplate<ARGITERATOR_BASE>::ComputeReturnFlags()
{
    CONTRACTL
    {
        INSTANCE_CHECK;
        if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;

Review comment (refactor):
I would like to see comments on this logic. It looks as if the SLOT_SIZE and STACK_ALIGNMENT are both constants, can't we simplify this? In the sense of `std::min(align, INTERP_STACK_ALIGNMENT)`?

Code after:
            assert(m_ofsStack == 0); // pass tail in first stack slot

            int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + lastReg * TARGET_POINTER_SIZE;
            m_idxGenReg = NUM_ARGUMENT_REGISTERS;
            m_ofsStack = TARGET_POINTER_SIZE;
            return argOfs;
        }
    }

    // Pass argument entirely on stack
    int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
    m_ofsStack += ALIGN_UP(cbArg, TARGET_POINTER_SIZE);

    return argOfs;
#elif defined(TARGET_WASM)

    unsigned align;
    if (argType == ELEMENT_TYPE_VALUETYPE)
    {
        align = std::clamp(CEEInfo::getClassAlignmentRequirementStatic(thValueType.GetMethodTable()), INTERP_STACK_SLOT_SIZE, INTERP_STACK_ALIGNMENT);
    }
    else
    {
        align = INTERP_STACK_SLOT_SIZE;
    }

    if (HasRetBuffArg())
    {
        // the slot for retbuf arg will be removed before the actual call
        m_ofsStack = ALIGN_UP(m_ofsStack - INTERP_STACK_SLOT_SIZE, align) + INTERP_STACK_SLOT_SIZE;
    }
    else
    {
        m_ofsStack = ALIGN_UP(m_ofsStack, align);
    }

    int cbArg = ALIGN_UP(argSize, INTERP_STACK_SLOT_SIZE);
    int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;

    m_ofsStack += cbArg;

    return argOfs;
#else
    PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
    return TransitionBlock::InvalidOffset;
#endif
}

template<class ARGITERATOR_BASE>
void ArgIteratorTemplate<ARGITERATOR_BASE>::ComputeReturnFlags()
{