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

Commit

Permalink
Wasm: RhpNewArrayAlign8 use non-padded size when going to the slow pa…
Browse files Browse the repository at this point in the history
…th (#8324)

* RhpNewArrayAlign8 use non-padded size when going to the slow path and RhpGcAlloc

* remove padding from slow path for RhpNewFastMisalign and RhpNewFastAlign8

* add overflow checks for 32bit host

* #if out align 8 methods for HOST_64BIT.  Change overflow check for padding to not use 64 bit arithmetic
  • Loading branch information
yowl committed Sep 25, 2020
1 parent 64389da commit 145402e
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 42 deletions.
97 changes: 61 additions & 36 deletions src/Native/Runtime/portable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFast, (EEType* pEEType))

size_t size = pEEType->get_BaseSize();

UInt8* result = acontext->alloc_ptr;
UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
UInt8* alloc_ptr = acontext->alloc_ptr;
ASSERT(alloc_ptr <= acontext->alloc_limit);
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= size)
{
acontext->alloc_ptr = advance;
pObject = (Object *)result;
acontext->alloc_ptr = alloc_ptr + size;
pObject = (Object *)alloc_ptr;
pObject->set_EEType(pEEType);
return pObject;
}
Expand Down Expand Up @@ -147,12 +147,12 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArray, (EEType * pArrayEEType, int numElement
size = ALIGN_UP(size, sizeof(UIntNative));
}

UInt8* result = acontext->alloc_ptr;
UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
UInt8* alloc_ptr = acontext->alloc_ptr;
ASSERT(alloc_ptr <= acontext->alloc_limit);
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= size)
{
acontext->alloc_ptr = advance;
pObject = (Array *)result;
acontext->alloc_ptr = alloc_ptr + size;
pObject = (Array *)alloc_ptr;
pObject->set_EEType(pArrayEEType);
pObject->InitArrayLength((UInt32)numElements);
return pObject;
Expand Down Expand Up @@ -192,6 +192,7 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFinalizableAlign8, (EEType* pEEType))
return pObject;
}

#ifndef HOST_64BIT
COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
{
ASSERT(pEEType->RequiresAlign8());
Expand All @@ -207,20 +208,29 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
UInt8* result = acontext->alloc_ptr;

int requiresPadding = ((uint32_t)result) & 7;
if (requiresPadding) size += 12;
UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
size_t paddedSize = size;
if (requiresPadding)
{
acontext->alloc_ptr = advance;
if(paddedSize > SIZE_MAX - 12)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
}
paddedSize += 12;
}

UInt8* alloc_ptr = acontext->alloc_ptr;
ASSERT(alloc_ptr <= acontext->alloc_limit);
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
{
acontext->alloc_ptr = alloc_ptr + paddedSize;
if (requiresPadding)
{
Object* dummy = (Object*)result;
Object* dummy = (Object*)alloc_ptr;
dummy->set_EEType(g_pFreeObjectEEType);
result += 12;
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
}
pObject = (Object*)result;
pObject = (Object *)alloc_ptr;
pObject->set_EEType(pEEType);

return pObject;
}

Expand All @@ -247,20 +257,28 @@ COOP_PINVOKE_HELPER(Object*, RhpNewFastMisalign, (EEType* pEEType))
UInt8* result = acontext->alloc_ptr;

int requiresPadding = (((uint32_t)result) & 7) != 4;
if (requiresPadding) size += 12;
UInt8* advance = result + size;
if (advance <= acontext->alloc_limit)
size_t paddedSize = size;
if (requiresPadding)
{
acontext->alloc_ptr = advance;
if(paddedSize > SIZE_MAX - 12)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
}
paddedSize += 12;
}
UInt8* alloc_ptr = acontext->alloc_ptr;
ASSERT(alloc_ptr <= acontext->alloc_limit);
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
{
acontext->alloc_ptr = alloc_ptr + paddedSize;
if (requiresPadding)
{
Object* dummy = (Object*)result;
Object* dummy = (Object*)alloc_ptr;
dummy->set_EEType(g_pFreeObjectEEType);
result += 12;
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
}
pObject = (Object*)result;
pObject = (Object *)alloc_ptr;
pObject->set_EEType(pEEType);

return pObject;
}

Expand Down Expand Up @@ -293,7 +311,6 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE
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)
Expand All @@ -309,26 +326,33 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE
}
}
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)
size_t paddedSize = size;
if (requiresAlignObject)
{
acontext->alloc_ptr = advance;
if(paddedSize > SIZE_MAX - 12)
{
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
}
paddedSize += 12;
}
UInt8* alloc_ptr = acontext->alloc_ptr;
ASSERT(alloc_ptr <= acontext->alloc_limit);
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
{
acontext->alloc_ptr = alloc_ptr + paddedSize;
if (requiresAlignObject)
{
Object* dummy = (Object*)result;
Object* dummy = (Object*)alloc_ptr;
dummy->set_EEType(g_pFreeObjectEEType);
result += 12;
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
}
pObject = (Array*)result;
pObject = (Array*)alloc_ptr;
pObject->set_EEType(pArrayEEType);
pObject->InitArrayLength((UInt32)numElements);
return pObject;
Expand All @@ -347,6 +371,7 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE

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

COOP_PINVOKE_HELPER(void, RhpInitialDynamicInterfaceDispatch, ())
Expand Down
84 changes: 78 additions & 6 deletions tests/src/Simple/HelloWasm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Specialized;

#if TARGET_WINDOWS
using CpObj;
Expand Down Expand Up @@ -386,7 +387,7 @@ private static void TestGC()

var genOfNewObject = GC.GetGeneration(new object());
PrintLine("Generation of new object " + genOfNewObject.ToString());
if(genOfNewObject != 0)
if (genOfNewObject != 0)
{
FailTest("Gen of new object was " + genOfNewObject);
return;
Expand All @@ -399,13 +400,18 @@ private static void TestGC()
FailTest("object alive when has no references");
return;
}
// create enough arrays to go over 5GB which should force older arrays to get collected
// use array of size 1MB, then iterate 5*1024 times
for(var i = 0; i < 5 * 1024; i++)
for (var i = 0; i < 3; i++)
{
var a = new int[256 * 1024]; // ints are 4 bytes so this is 1MB
PrintString("GC Collection Count " + i.ToString() + " ");
PrintLine(GC.CollectionCount(i).ToString());
}
if(!TestCreateDifferentObjects())
{
FailTest("Failed test for creating/collecting different objects");
}
for(var i = 0; i < 3; i++)
GC.Collect();
GC.Collect();
for (var i = 0; i < 3; i++)
{
PrintString("GC Collection Count " + i.ToString() + " ");
PrintLine(GC.CollectionCount(i).ToString());
Expand All @@ -425,6 +431,72 @@ private static void TestGC()
EndTest(TestGeneration2Rooting());
}

struct MiniRandom
{
private uint _val;

public MiniRandom(uint seed)
{
_val = seed;
}

public uint Next()
{
_val ^= (_val << 13);
_val ^= (_val >> 7);
_val ^= (_val << 17);
return _val;
}
}

class F4 { internal int i; }
class F8 { internal long l; }
class F2Plus8 { internal short s; internal long l; }
class CDisp : IDisposable { public void Dispose() { } }
struct StructF48 { internal int i1; internal long l2; }
private static bool TestCreateDifferentObjects()
{
var mr = new MiniRandom(257);
var keptObjects = new object[100];
for (var i = 0; i < 1000000; i++)
{
var r = mr.Next();
object o;
switch (r % 8)
{
case 0:
o = new F4 { i = 1, };
break;
case 1:
o = new F8 { l = 4 };
break;
case 2:
o = new F2Plus8 { l = 5, s = 6 };
break;
case 3:
o = i.ToString();
break;
case 4:
o = new long[10000];
break;
case 5:
o = new int[10000];
break;
case 6:
o = new StructF48 { i1 = 7, l2 = 8 };
break;
case 7:
o = new CDisp();
break;
default:
o = null;
break;
}
keptObjects[r % 100] = o;
}
return true;
}

private static Parent aParent;
private static ParentOfStructWithObjRefs aParentOfStructWithObjRefs;
private static WeakReference childRef;
Expand Down

0 comments on commit 145402e

Please sign in to comment.