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

Code before:
#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;
    }

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

    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;
        if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
        if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
        MODE_ANY;
    }
    CONTRACTL_END

    TypeHandle thValueType;
    CorElementType type = this->GetReturnType(&thValueType);

    DWORD flags = RETURN_FLAGS_COMPUTED;
    switch (type)
    {
    case ELEMENT_TYPE_TYPEDBYREF:
#ifdef ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE
        if (sizeof(TypedByRef) > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE)
            flags |= RETURN_HAS_RET_BUFFER;
#else

Review comment (suggestion):
In the TARGET_WASM GetNextOffset path, argOfs uses ALIGN_UP(m_ofsStack, align) but m_ofsStack is then incremented by only cbArg. When align > INTERP_STACK_SLOT_SIZE, this drops the padding from the running offset, so the next argument can overlap the previous one. Update m_ofsStack to include the alignment padding (e.g., align m_ofsStack first, then add cbArg).

Code after:

    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()
{
    CONTRACTL
    {
        INSTANCE_CHECK;
        if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
        if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
        if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
        MODE_ANY;
    }
    CONTRACTL_END

    TypeHandle thValueType;
    CorElementType type = this->GetReturnType(&thValueType);

    DWORD flags = RETURN_FLAGS_COMPUTED;
    switch (type)