Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Wasm: Align classes and arrays with 64 bit types at 8 byte #8255

Merged
merged 7 commits into from
Aug 13, 2020
Merged
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
4 changes: 2 additions & 2 deletions src/Common/src/TypeSystem/Common/TargetDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment)
switch (Architecture)
{
case TargetArchitecture.ARM:
// ARM supports two alignments for objects on the GC heap (4 byte and 8 byte)
case TargetArchitecture.Wasm32:
// ARM & Wasm32 support two alignments for objects on the GC heap (4 byte and 8 byte)
if (fieldAlignment.IsIndeterminate)
return LayoutInt.Indeterminate;

Expand All @@ -286,7 +287,6 @@ public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment)
case TargetArchitecture.ARM64:
return new LayoutInt(8);
case TargetArchitecture.X86:
case TargetArchitecture.Wasm32:
return new LayoutInt(4);
default:
throw new NotSupportedException();
Expand Down
4 changes: 2 additions & 2 deletions src/ILCompiler.Compiler/src/Compiler/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ public static bool IsArrayTypeWithoutGenericInterfaces(this TypeDesc type)

/// <summary>
/// Determines whether an object of type '<paramref name="type"/>' requires 8-byte alignment on
/// 32bit ARM architectures.
/// 32bit ARM or 32bit Wasm architectures.
/// </summary>
public static bool RequiresAlign8(this TypeDesc type)
{
if (type.Context.Target.Architecture != TargetArchitecture.ARM)
if (type.Context.Target.Architecture != TargetArchitecture.ARM && type.Context.Target.Architecture != TargetArchitecture.Wasm32)
{
return false;
}
Expand Down
13 changes: 11 additions & 2 deletions src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4944,9 +4944,18 @@ private void ImportNewArray(int token)
else
{
arguments = new StackEntry[] { new LoadExpressionEntry(StackValueKind.ValueType, "eeType", GetEETypePointerForTypeDesc(runtimeDeterminedArrayType, true), eeTypeDesc), sizeOfArray };
//TODO: call GetNewArrayHelperForType from JitHelper.cs (needs refactoring)
}
PushNonNull(CallRuntime(_compilation.TypeSystemContext, InternalCalls, "RhpNewArray", arguments, runtimeDeterminedArrayType));
var helper = GetNewArrayHelperForType(runtimeDeterminedArrayType);
PushNonNull(CallRuntime(_compilation.TypeSystemContext, InternalCalls, helper, arguments, runtimeDeterminedArrayType));
}

//TODO: copy of the same method in JitHelper.cs but that is internal
public static string GetNewArrayHelperForType(TypeDesc type)
{
if (type.RequiresAlign8())
return "RhpNewArrayAlign8";

return "RhpNewArray";
}

LLVMValueRef GetGenericContext()
Expand Down
1 change: 1 addition & 0 deletions src/Native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ elseif(CLR_CMAKE_TARGET_ARCH STREQUAL wasm)
set(CLR_CMAKE_PLATFORM_ARCH_WASM 1)
add_definitions(-DTARGET_WASM=1)
add_definitions(-DHOST_WASM=1)
add_definitions(-DFEATURE_64BIT_ALIGNMENT=1)
else()
clr_unknown_arch()
endif()
Expand Down
140 changes: 127 additions & 13 deletions src/Native/Runtime/portable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#include "GCMemoryHelpers.inl"

#if defined(USE_PORTABLE_HELPERS)

EXTERN_C REDHAWK_API void* REDHAWK_CALLCONV RhpGcAlloc(EEType *pEEType, UInt32 uFlags, UIntNative cbSize, void * pTransitionFrame);
EXTERN_C REDHAWK_API void* REDHAWK_CALLCONV RhpPublishObject(void* pObject, UIntNative cbSize);

Expand Down Expand Up @@ -88,7 +87,9 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFast, (EEType* pEEType))
return pObject;
}

#define GC_ALLOC_FINALIZE 0x1 // TODO: Defined in gc.h
#define GC_ALLOC_FINALIZE 0x1 // TODO: Defined in gc.h
#define GC_ALLOC_ALIGN8_BIAS 0x4 // TODO: Defined in gc.h
#define GC_ALLOC_ALIGN8 0x8 // TODO: Defined in gc.h
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried including gcinterface.h but that seems to have other dependencies


COOP_PINVOKE_HELPER(Object *, RhpNewFinalizable, (EEType* pEEType))
{
Expand Down Expand Up @@ -180,36 +181,149 @@ COOP_PINVOKE_HELPER(String *, RhNewString, (EEType * pArrayEEType, int numElemen

#endif
#if defined(USE_PORTABLE_HELPERS)
#if defined(FEATURE_64BIT_ALIGNMENT)

GPTR_DECL(EEType, g_pFreeObjectEEType);

#ifdef HOST_ARM
COOP_PINVOKE_HELPER(Object *, RhpNewFinalizableAlign8, (EEType* pEEType))
{
Object * pObject = nullptr;
/* TODO */ ASSERT_UNCONDITIONALLY("NYI");
/* Not reachable as finalizable types are never align8 */ ASSERT_UNCONDITIONALLY("UNREACHABLE");
return pObject;
}

COOP_PINVOKE_HELPER(Object *, RhpNewFastMisalign, (EEType* pEEType))
COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
{
Object * pObject = nullptr;
/* TODO */ ASSERT_UNCONDITIONALLY("NYI");
ASSERT(pEEType->RequiresAlign8());
ASSERT(!pEEType->HasFinalizer());

Thread* pCurThread = ThreadStore::GetCurrentThread();
gc_alloc_context* acontext = pCurThread->GetAllocContext();
Object* pObject;

size_t size = pEEType->get_BaseSize();
size = (size + (sizeof(UIntNative) - 1)) & ~(sizeof(UIntNative) - 1);

UInt8* result = acontext->alloc_ptr;

int requiresPadding = ((uint32_t)result) & 7;
if (requiresPadding) size += 12;
UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
{
acontext->alloc_ptr = advance;
if (requiresPadding)
{
Object* dummy = (Object*)result;
dummy->set_EEType(g_pFreeObjectEEType);
result += 12;
}
pObject = (Object*)result;
pObject->set_EEType(pEEType);

return pObject;
}

pObject = (Object*)RhpGcAlloc(pEEType, GC_ALLOC_ALIGN8, size, NULL);
if (pObject == nullptr)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw OOM
}
pObject->set_EEType(pEEType);

if (size >= RH_LARGE_OBJECT_SIZE)
RhpPublishObject(pObject, size);

return pObject;
}

COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
COOP_PINVOKE_HELPER(Object*, RhpNewFastMisalign, (EEType* pEEType))
{
Object * pObject = nullptr;
/* TODO */ ASSERT_UNCONDITIONALLY("NYI");
size_t size = pEEType->get_BaseSize();
Object* pObject = (Object*)RhpGcAlloc(pEEType, GC_ALLOC_ALIGN8_BIAS, size, NULL);
if (pObject == nullptr)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw OOM
}
pObject->set_EEType(pEEType);

if (size >= RH_LARGE_OBJECT_SIZE)
RhpPublishObject(pObject, size);

return pObject;
}

COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numElements))
{
Array * pObject = nullptr;
/* TODO */ ASSERT_UNCONDITIONALLY("NYI");
ASSERT_MSG(pArrayEEType->RequiresAlign8(), "RhpNewArrayAlign8 called for a type that is not aligned 8");

Thread* pCurThread = ThreadStore::GetCurrentThread();
gc_alloc_context* acontext = pCurThread->GetAllocContext();
Array* pObject;

if (numElements < 0)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
}

size_t size;

UInt32 baseSize = pArrayEEType->get_BaseSize();
#ifndef HOST_64BIT
// if the element count is <= 0x10000, no overflow is possible because the component size is
// <= 0xffff, and thus the product is <= 0xffff0000, and the base size is only ~12 bytes
if (numElements > 0x10000)
{
// Perform the size computation using 64-bit integeres to detect overflow
uint64_t size64 = (uint64_t)baseSize + ((uint64_t)numElements * (uint64_t)pArrayEEType->get_ComponentSize());
size64 = (size64 + (sizeof(UIntNative) - 1)) & ~(sizeof(UIntNative) - 1);

size = (size_t)size64;
if (size != size64)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
}
}
else
#endif // !HOST_64BIT
{
size = (size_t)baseSize + ((size_t)numElements * (size_t)pArrayEEType->get_ComponentSize());
size = ALIGN_UP(size, sizeof(UIntNative));
}
UInt8* result = acontext->alloc_ptr;
int requiresAlignObject = ((uint32_t)result) & 7;
if (requiresAlignObject) size += 12;

UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
{
acontext->alloc_ptr = advance;
if (requiresAlignObject)
{
Object* dummy = (Object*)result;
dummy->set_EEType(g_pFreeObjectEEType);
result += 12;
}
pObject = (Array*)result;
pObject->set_EEType(pArrayEEType);
pObject->InitArrayLength((UInt32)numElements);
return pObject;
}

pObject = (Array*)RhpGcAlloc(pArrayEEType, GC_ALLOC_ALIGN8, size, NULL);
if (pObject == nullptr)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw OOM
}
pObject->set_EEType(pArrayEEType);
pObject->InitArrayLength((UInt32)numElements);

if (size >= RH_LARGE_OBJECT_SIZE)
RhpPublishObject(pObject, size);

return pObject;
}
#endif
#endif // defined(HOST_ARM) || defined(HOST_WASM)

COOP_PINVOKE_HELPER(void, RhpInitialDynamicInterfaceDispatch, ())
{
Expand Down
8 changes: 4 additions & 4 deletions src/Native/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17833,12 +17833,12 @@ uint8_t* gc_heap::find_object (uint8_t* interior)
{
// this is a pointer to a UOH object
heap_segment* seg = find_segment (interior, FALSE);
if (seg
if (seg)
{
#ifdef FEATURE_CONSERVATIVE_GC
&& (GCConfig::GetConservativeGC() || interior <= heap_segment_allocated(seg))
if ( interior >= heap_segment_allocated(seg))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as merged in dotnet/runtime#39905 . If this complicates merging, I can leave this PR as WIP.

return 0;
#endif
)
{
// If interior falls within the first free object at the beginning of a generation,
// we don't have brick entry for it, and we may incorrectly treat it as on large object heap.
int align_const = get_alignment_constant (heap_segment_read_only_p (seg)
Expand Down
3 changes: 3 additions & 0 deletions src/Runtime.Base/src/Runtime.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<PropertyGroup Condition="'$(Platform)' == 'armel'">
<DefineConstants>FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' == 'wasm'">
<DefineConstants>FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Include="System\Nullable.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@
<DefineConstants>INPLACE_RUNTIME;$(DefineConstants)</DefineConstants>
<DefineConstants Condition="'$(Platform)' == 'arm'">FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants>
<DefineConstants Condition="'$(Platform)' == 'armel'">FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants>
<DefineConstants Condition="'$(Platform)' == 'wasm'">FEATURE_64BIT_ALIGNMENT;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(InPlaceRuntime)' == 'true'">
<Compile Include="..\..\Runtime.Base\src\System\Diagnostics\Eval.cs">
Expand Down