Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2316,7 +2316,7 @@ public static int GetClassAlignmentRequirementStatic(DefType type)
}
}

if (type.Context.Target.Architecture == TargetArchitecture.ARM &&
if (type.Context.Target.SupportsAlign8 &&
alignment < 8 && type.RequiresAlign8())
{
// If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/tools/Common/JitInterface/WasmLowering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace Internal.JitInterface
{
public static class WasmLowering
public static partial class WasmLowering
{
// The Wasm "basic C ABI" passes structs that contain one
// primitive field as that primitive field.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
// pointer (the Crossgen2 way) to ensure 8-alignment for longs and doubles as required by the ARM32 ISA. Please note
// that for 16-alignment used by Vector128 this logic actually ensures that the fields are 16-misaligned
// (they are 16-aligned after the 4-byte or 8-byte method table pointer).
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && type.Context.Target.Architecture != TargetArchitecture.ARM)
if (!type.IsValueType && cumulativeInstanceFieldPos != LayoutInt.Zero && !type.Context.Target.SupportsAlign8)
{
offsetBias = type.Context.Target.LayoutPointerSize;
cumulativeInstanceFieldPos -= offsetBias;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1076,49 +1076,15 @@ public int GetNextOffset()
case TargetArchitecture.Wasm32:
{
bool isValueType = (argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
WasmValueType actualWasmAbiType = default(WasmValueType);

switch (argType)
int cbArg = ALIGN_UP(argSize, 8);
int align;
if (isValueType)
{
case CorElementType.ELEMENT_TYPE_VALUETYPE:
actualWasmAbiType = WasmLowering.LowerType(_argTypeHandle.GetRuntimeTypeHandle());
break;

case CorElementType.ELEMENT_TYPE_I8:
case CorElementType.ELEMENT_TYPE_U8:
actualWasmAbiType = WasmValueType.I64;
break;
case CorElementType.ELEMENT_TYPE_R8:
actualWasmAbiType = WasmValueType.F64;
break;
case CorElementType.ELEMENT_TYPE_R4:
actualWasmAbiType = WasmValueType.F32;
break;
default:
actualWasmAbiType = WasmValueType.I32;
break;
align = Math.Clamp(((DefType)_argTypeHandle.GetRuntimeTypeHandle()).InstanceFieldAlignment.AsInt, 8, 16);
}

int cbArg;
int align;
switch (actualWasmAbiType)
else
{
case WasmValueType.I64:
case WasmValueType.F64:
cbArg = 8;
align = 8;
break;
case WasmValueType.I32:
case WasmValueType.F32:
cbArg = 8;
align = 8;
break;
case WasmValueType.V128:
cbArg = 16;
align = 16;
break;
default:
throw new Exception(); // These are the only WasmValueTypes defined in our transition block handling
}

_wasmOfsStack = ALIGN_UP(_wasmOfsStack, align);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp
break;
}

if (IsWasm32)
{
// Wasm doesn't use a ret buffer for returning structs in the interpreter calling convention, which is the TransitionBlock convention on Wasm platforms.
break;
}

uint size = (uint)thRetType.GetSize();

if (IsX86 || IsX64)
Expand Down Expand Up @@ -774,7 +780,7 @@ private class Wasm32TransitionBlock : TransitionBlock

public override bool IsArgPassedByRef(TypeHandle th)
{
return WasmLowering.LowerToAbiType(th.GetRuntimeTypeHandle()) == null;
return false;
}

public override int StackElemSize(int parmSize, bool isValueType, bool isFloatHfa)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ protected override void EmitCode(NodeFactory factory, ref Wasm.WasmEmitter instr
while ((argOffset = argit.GetNextOffset()) != TransitionBlock.InvalidOffset)
{
offsets[argIndex] = argOffset;
isIndirectStructArg[argIndex] = argit.IsArgPassedByRef() && argit.IsValueType();
isIndirectStructArg[argIndex] = WasmLowering.CurrentArgLowersValueTypeToPassAsByref(argit);
argIndex++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ protected override void EmitCode(NodeFactory factory, ref Wasm.WasmEmitter instr
while ((argOffset = argit.GetNextOffset()) != TransitionBlock.InvalidOffset)
{
interpOffsets[argIndex] = argOffset - sizeOfTransitionBlock;
isIndirectStructArg[argIndex] = argit.IsArgPassedByRef() && argit.IsValueType();
isIndirectStructArg[argIndex] = WasmLowering.CurrentArgLowersValueTypeToPassAsByref(argit);
argIndex++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ protected override void EmitCode(NodeFactory factory, ref Wasm.WasmEmitter instr
while ((argOffset = argit.GetNextOffset()) != TransitionBlock.InvalidOffset)
{
offsets[argIndex] = argOffset;
isIndirectStructArg[argIndex] = argit.IsArgPassedByRef() && argit.IsValueType();
isIndirectStructArg[argIndex] = WasmLowering.CurrentArgLowersValueTypeToPassAsByref(argit);
argIndex++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@
<Compile Include="Compiler\SystemObjectFieldLayoutAlgorithm.cs" />
<Compile Include="IL\ReadyToRunILProvider.cs" />
<Compile Include="JitInterface\CorInfoImpl.ReadyToRun.cs" />
<Compile Include="JitInterface\WasmLowering.ReadyToRun.cs" />
<Compile Include="ObjectWriter\TargetExtensions.cs" />
<Compile Include="TypeSystem\MethodDescExtensions.cs" />
<Compile Include="TypeSystem\Mutable\MutableModule.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using ILCompiler;
using ILCompiler.DependencyAnalysis.Wasm;
using ILCompiler.DependencyAnalysis.ReadyToRun;

using Internal.TypeSystem;

namespace Internal.JitInterface
{
public static partial class WasmLowering
{
internal static bool CurrentArgLowersValueTypeToPassAsByref(ArgIterator argit)
{
if (argit.IsValueType())
{
// Check to see if this argument lowers to a byref on the wasm side
TypeHandle typeHandle;
argit.GetArgType(out typeHandle);
if (WasmLowering.LowerToAbiType(typeHandle.GetRuntimeTypeHandle()) == null)
{
return true;
}
}

return false;
}
}
}
1 change: 1 addition & 0 deletions src/coreclr/vm/callhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct CallDescrData
size_t nArgsSize;
bool hasThis;
bool hasRetBuff;
void* pRetBuffArg;
#endif // TARGET_WASM

#ifdef CALLDESCR_RETBUFFARGREG
Expand Down
17 changes: 8 additions & 9 deletions src/coreclr/vm/callingconvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -1919,15 +1919,9 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
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);
}
_ASSERTE(!HasRetBuffArg());

m_ofsStack = ALIGN_UP(m_ofsStack, align);

int cbArg = ALIGN_UP(argSize, INTERP_STACK_SLOT_SIZE);
int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
Expand Down Expand Up @@ -2075,6 +2069,11 @@ void ArgIteratorTemplate<ARGITERATOR_BASE>::ComputeReturnFlags()
break;
}

#ifdef TARGET_WASM
// WebAssembly ArgIterator follows the Interpreter calling convention which does not use a return buffer arg in the normal argument stream
flags &= ~RETURN_HAS_RET_BUFFER;
#endif

m_dwFlags |= flags;
}

Expand Down
25 changes: 24 additions & 1 deletion src/coreclr/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,13 @@ class ArgIteratorBaseForMethodInvoke
SIGNATURENATIVEREF * m_ppNativeSig;
bool m_fHasThis;

public:
FORCEINLINE CorElementType GetReturnType(TypeHandle * pthValueType)
{
WRAPPER_NO_CONTRACT;
return (*pthValueType = (*m_ppNativeSig)->GetReturnTypeHandle()).GetInternalCorElementType();
}
protected:

FORCEINLINE CorElementType GetNextArgumentType(DWORD iArg, TypeHandle * pthValueType)
{
Expand Down Expand Up @@ -423,7 +425,20 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
// WASM-TODO: this is now called from the interpreter, so the arguments layout is OK. reconsider with codegen
callDescrData.nArgsSize = nStackBytes;
callDescrData.hasThis = argit.HasThis();
callDescrData.hasRetBuff = argit.HasRetBuffArg();

TypeHandle thValueType;
CorElementType type = argit.GetReturnType(&thValueType);
DWORD retSize = 0;
if (type == ELEMENT_TYPE_TYPEDBYREF)
{
retSize = sizeof(TypedByRef);
}
else if (type == ELEMENT_TYPE_VALUETYPE)
{
retSize = thValueType.GetSize();
}

callDescrData.hasRetBuff = retSize > sizeof(callDescrData.returnValue);
#endif // TARGET_WASM

// This is duplicated logic from MethodDesc::GetCallTarget
Expand Down Expand Up @@ -453,7 +468,11 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
TypeHandle retTH = gc.pSig->GetReturnTypeHandle();

TypeHandle refReturnTargetTH; // Valid only if retType == ELEMENT_TYPE_BYREF. Caches the TypeHandle of the byref target.
#ifdef TARGET_WASM
BOOL fHasRetBuffArg = callDescrData.hasRetBuff;
#else
BOOL fHasRetBuffArg = argit.HasRetBuffArg();
#endif
CorElementType retType = retTH.GetSignatureCorElementType();
BOOL hasValueTypeReturn = retTH.IsValueType() && retType != ELEMENT_TYPE_VOID;
_ASSERTE(hasValueTypeReturn || !fHasRetBuffArg); // only valuetypes are returned via a return buffer.
Expand Down Expand Up @@ -538,7 +557,11 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_InvokeMethod(
// buffer which will be copied to gc.retVal later.
pLocalRetBuf = _alloca(localRetBufSize);
ZeroMemory(pLocalRetBuf, localRetBufSize);
#ifdef TARGET_WASM
callDescrData.pRetBuffArg = reinterpret_cast<decltype(callDescrData.pRetBuffArg)>(pLocalRetBuf);
#else
*((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pLocalRetBuf;
#endif
if (pMT->ContainsGCPointers())
{
pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pLocalRetBuf, pMT, pValueClasses);
Expand Down
19 changes: 3 additions & 16 deletions src/coreclr/vm/wasm/calldescrworkerwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
// Forward declaration
void ExecuteInterpretedMethodWithArgs(TADDR targetIp, int8_t* args, size_t argSize, void* retBuff, PCODE callerIp);

#define SPECIAL_ARG_ADDR(pos) (void**)(((int8_t*)pCallDescrData->pSrc) + ((pos)*INTERP_STACK_SLOT_SIZE))

extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData* pCallDescrData)
{
_ASSERTE(pCallDescrData != NULL);
Expand All @@ -30,25 +28,14 @@ extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData* pCallDescrData)

size_t argsSize = pCallDescrData->nArgsSize;
void* retBuff;
int8_t* args;
int8_t* args = (int8_t*)pCallDescrData->pSrc;
if (pCallDescrData->hasRetBuff)
{
argsSize -= INTERP_STACK_SLOT_SIZE;
if (pCallDescrData->hasThis)
{
retBuff = *SPECIAL_ARG_ADDR(1);
*SPECIAL_ARG_ADDR(1) = *SPECIAL_ARG_ADDR(0);
}
else
{
retBuff = *SPECIAL_ARG_ADDR(0);
}
args = (int8_t*)SPECIAL_ARG_ADDR(1);
retBuff = pCallDescrData->pRetBuffArg;
}
else
{
args = (int8_t*)pCallDescrData->pSrc;
retBuff = pCallDescrData->returnValue;
retBuff = &pCallDescrData->returnValue;
}

ExecuteInterpretedMethodWithArgs((TADDR)targetIp, args, argsSize, retBuff, (PCODE)&CallDescrWorkerInternal);
Expand Down
Loading