Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 82b90ee

Browse files
committed
Avoid allocations of size 0 since they mess with the nursery. Explicitly specify how much memory to preserve when calling Realloc. Try recycling large allocs ASAP.
1 parent fee2ca4 commit 82b90ee

5 files changed

Lines changed: 101 additions & 35 deletions

File tree

include/hx/GC.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ namespace hx
114114
void *InternalNew(int inSize,bool inIsObject);
115115

116116
// Used internall - realloc array data
117-
void *InternalRealloc(void *inData,int inSize,bool inAllowExpansion=false);
117+
void *InternalRealloc(int inFromSize, void *inData,int inSize,bool inAllowExpansion=false);
118+
119+
void InternalReleaseMem(void *inMem);
118120

119121
unsigned int ObjectSizeSafe(void *inData);
120122

src/Array.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,20 @@ void ArrayBase::reserve(int inSize) const
4242
{
4343
if (mAlloc<inSize)
4444
{
45-
int bytes = inSize * GetElementSize();
45+
int elemSize = GetElementSize();
46+
int bytes = inSize * elemSize;
4647

4748
if (mBase)
4849
{
4950
bool wasUnamanaged = mAlloc<0;
5051
if (wasUnamanaged)
5152
{
5253
char *base=(char *)hx::InternalNew(bytes,false);
53-
memcpy(base,mBase,length*GetElementSize());
54+
memcpy(base,mBase,length*elemSize);
5455
mBase = base;
5556
}
5657
else
57-
mBase = (char *)hx::InternalRealloc(mBase, bytes );
58+
mBase = (char *)hx::InternalRealloc(length*elemSize,mBase, bytes );
5859
}
5960
else
6061
{
@@ -101,12 +102,12 @@ void ArrayBase::Realloc(int inSize) const
101102
if (wasUnamanaged)
102103
{
103104
char *base=(char *)hx::InternalNew(bytes,false);
104-
memcpy(base,mBase,length*GetElementSize());
105+
memcpy(base,mBase,length*elemSize);
105106
mBase = base;
106107
}
107108
else
108109
{
109-
mBase = (char *)hx::InternalRealloc(mBase, bytes, true);
110+
mBase = (char *)hx::InternalRealloc(length*elemSize,mBase, bytes, true);
110111
int o = bytes;
111112
bytes = hx::ObjectSizeSafe(mBase);
112113
}
@@ -213,21 +214,28 @@ String ArrayBase::toString()
213214

214215
void ArrayBase::__SetSizeExact(int inSize)
215216
{
216-
if (inSize!=length || inSize!=mAlloc)
217+
if (inSize==0)
217218
{
218-
int bytes = inSize * GetElementSize();
219+
InternalReleaseMem(mBase);
220+
mBase = 0;
221+
mAlloc = length = 0;
222+
}
223+
else if (inSize!=length || inSize!=mAlloc)
224+
{
225+
int elemSize = GetElementSize();
226+
int bytes = inSize * elemSize;
219227
if (mBase)
220228
{
221229
bool wasUnamanaged = mAlloc<0;
222230

223231
if (wasUnamanaged)
224232
{
225233
char *base=(char *)(AllocAtomic() ? hx::NewGCPrivate(0,bytes) : hx::NewGCBytes(0,bytes));
226-
memcpy(base,mBase,std::min(length,inSize)*GetElementSize());
234+
memcpy(base,mBase,std::min(length,inSize)*elemSize);
227235
mBase = base;
228236
}
229237
else
230-
mBase = (char *)hx::InternalRealloc(mBase, bytes );
238+
mBase = (char *)hx::InternalRealloc(length*elemSize,mBase, bytes );
231239
}
232240
else if (AllocAtomic())
233241
{
@@ -732,6 +740,7 @@ void ArrayBase::__boot()
732740

733741
bool DynamicEq(const Dynamic &a, const Dynamic &b)
734742
{
743+
// ? return hx::IsInstanceEq(a,b);
735744
return hx::IsEq(a,b);
736745
}
737746

src/hx/Hash.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ struct Hash : public HashBase< typename ELEMENT::Key >
328328
#endif
329329
mask = inNewCount-1;
330330
//printf("expand %d -> %d\n",bucketCount, inNewCount);
331-
bucket = (Element **)InternalRealloc(bucket,inNewCount*sizeof(ELEMENT *));
331+
bucket = (Element **)InternalRealloc(bucketCount*sizeof(ELEMENT *), bucket,inNewCount*sizeof(ELEMENT *));
332332
HX_OBJ_WB_GET(this, bucket);
333333
//for(int b=bucketCount;b<inNewCount;b++)
334334
// bucket[b] = 0;
@@ -369,6 +369,7 @@ struct Hash : public HashBase< typename ELEMENT::Key >
369369

370370
void compact()
371371
{
372+
int origSize = bucketCount;
372373
int newSize = bucketCount>>1;
373374
// printf("compact -> %d\n", newSize);
374375
mask = newSize-1;
@@ -392,7 +393,7 @@ struct Hash : public HashBase< typename ELEMENT::Key >
392393
}
393394
}
394395
bucketCount = newSize;
395-
bucket = (Element **)InternalRealloc(bucket, sizeof(ELEMENT *)*bucketCount );
396+
bucket = (Element **)InternalRealloc(origSize*sizeof(ELEMENT *),bucket, sizeof(ELEMENT *)*bucketCount );
396397
HX_OBJ_WB_GET(this, bucket);
397398
}
398399

src/hx/gc/Immix.cpp

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,14 +2815,17 @@ void *InternalCreateConstBuffer(const void *inData,int inSize,bool inAddStringHa
28152815
{
28162816
memcpy(result,inData,inSize);
28172817
}
2818-
else
2818+
else if (inSize)
28192819
{
28202820
ZERO_MEM(result,inSize);
28212821
}
28222822

28232823
return result;
28242824
}
28252825

2826+
// Used when the allocation size is zero for a non-null pointer
2827+
void *emptyAlloc = InternalCreateConstBuffer(0,0,false);
2828+
28262829

28272830
} // namespace hx
28282831

@@ -3116,6 +3119,31 @@ class GlobalAllocator
31163119
}
31173120
}
31183121

3122+
void FreeLarge(void *inLarge)
3123+
{
3124+
((unsigned char *)inLarge)[HX_ENDIAN_MARK_ID_BYTE] = 0;
3125+
// AllocLarge will not lock this list unless it decides there is a suitable
3126+
// value, so we can't doa realloc without potentially crashing it.
3127+
if (largeObjectRecycle.hasExtraCapacity(1))
3128+
{
3129+
unsigned int *blob = ((unsigned int *)inLarge) - 2;
3130+
unsigned int size = *blob;
3131+
mLargeListLock.Lock();
3132+
mLargeAllocated -= size;
3133+
// Could somehow keep it in the list, but mark as recycled?
3134+
mLargeList.qerase_val(blob);
3135+
// We could maybe free anyhow?
3136+
if (!largeObjectRecycle.hasExtraCapacity(1))
3137+
{
3138+
mLargeListLock.Unlock();
3139+
HxFree(blob);
3140+
return;
3141+
}
3142+
largeObjectRecycle.push(blob);
3143+
mLargeListLock.Unlock();
3144+
}
3145+
}
3146+
31193147
void *AllocLarge(int inSize, bool inClear)
31203148
{
31213149
if (hx::gPauseForCollect)
@@ -6027,6 +6055,9 @@ class LocalAllocator : public hx::StackContext
60276055
PauseForCollect();
60286056
#endif
60296057

6058+
if (inSize==0)
6059+
return hx::emptyAlloc;
6060+
60306061
#if defined(HXCPP_VISIT_ALLOCS) && defined(HXCPP_M64)
60316062
// Make sure we can fit a relocation pointer
60326063
int allocSize = sizeof(int) + std::max(8,inSize);
@@ -6485,6 +6516,9 @@ inline unsigned int ObjectSize(void *inData)
64856516
unsigned int ObjectSizeSafe(void *inData)
64866517
{
64876518
unsigned int header = ((unsigned int *)(inData))[-1];
6519+
if (header & HX_GC_CONST_ALLOC_BIT)
6520+
return 0;
6521+
64886522
#ifdef HXCPP_GC_NURSERY
64896523
if (!(header & 0xff000000))
64906524
{
@@ -6495,6 +6529,7 @@ unsigned int ObjectSizeSafe(void *inData)
64956529
}
64966530
#endif
64976531

6532+
64986533
return (header & IMMIX_ALLOC_ROW_COUNT) ?
64996534
( (header & IMMIX_ALLOC_SIZE_MASK) >> IMMIX_ALLOC_SIZE_SHIFT) :
65006535
((unsigned int *)(inData))[-2];
@@ -6505,11 +6540,29 @@ void GCChangeManagedMemory(int inDelta, const char *inWhy)
65056540
sGlobalAlloc->onMemoryChange(inDelta, inWhy);
65066541
}
65076542

6543+
void InternalReleaseMem(void *inMem)
6544+
{
6545+
if (inMem)
6546+
{
6547+
unsigned int s = ObjectSizeSafe(inMem);
6548+
if (s>=IMMIX_LARGE_OBJ_SIZE)
6549+
{
6550+
//Can release asap
6551+
sGlobalAlloc->FreeLarge(inMem);
6552+
}
6553+
}
6554+
}
6555+
6556+
65086557

6509-
void *InternalRealloc(void *inData,int inSize, bool inExpand)
6558+
void *InternalRealloc(int inFromSize, void *inData,int inSize, bool inExpand)
65106559
{
6511-
if (inData==0)
6560+
if (inData==0 || inFromSize==0)
6561+
{
6562+
if (inData)
6563+
InternalReleaseMem(inData);
65126564
return hx::InternalNew(inSize,false);
6565+
}
65136566

65146567
HX_STACK_FRAME("GC", "realloc", 0, "GC::relloc", __FILE__ , __LINE__, 0)
65156568

@@ -6522,15 +6575,16 @@ void *InternalRealloc(void *inData,int inSize, bool inExpand)
65226575
sgAllocsSinceLastSpam++;
65236576
#endif
65246577

6525-
unsigned int s = ObjectSizeSafe(inData);
6526-
65276578
void *new_data = 0;
6528-
6529-
if (inSize>=IMMIX_LARGE_OBJ_SIZE)
6579+
if (inSize==0)
6580+
{
6581+
new_data = hx::emptyAlloc;
6582+
}
6583+
else if (inSize>=IMMIX_LARGE_OBJ_SIZE)
65306584
{
65316585
new_data = sGlobalAlloc->AllocLarge(inSize, false);
6532-
if (inSize>s)
6533-
ZERO_MEM((char *)new_data + s,inSize-s);
6586+
if (inSize>inFromSize)
6587+
ZERO_MEM((char *)new_data + inFromSize,inSize-inFromSize);
65346588
}
65356589
else
65366590
{
@@ -6541,12 +6595,13 @@ void *InternalRealloc(void *inData,int inSize, bool inExpand)
65416595
new_data = tla->CallAlloc(8,0);
65426596
else
65436597
#endif
6598+
{
6599+
inSize = (inSize+3) & ~3;
6600+
if (inExpand)
6601+
tla->ExpandAlloc(inSize);
65446602

6545-
inSize = (inSize+3) & ~3;
6546-
if (inExpand)
6547-
tla->ExpandAlloc(inSize);
6548-
6549-
new_data = tla->CallAlloc(inSize,0);
6603+
new_data = tla->CallAlloc(inSize,0);
6604+
}
65506605
}
65516606

65526607

@@ -6555,17 +6610,12 @@ void *InternalRealloc(void *inData,int inSize, bool inExpand)
65556610
__hxt_gc_realloc(inData, new_data, inSize);
65566611
#endif
65576612

6558-
int min_size = s < inSize ? s : inSize;
6613+
int min_size = inFromSize < inSize ? inFromSize : inSize;
65596614

6560-
memcpy(new_data, inData, min_size );
6615+
if (min_size)
6616+
memcpy(new_data, inData, min_size );
65616617

6562-
#ifdef HXCPP_GC_GENERATIONAL
6563-
if (s>=IMMIX_LARGE_OBJ_SIZE && sGcMode==gcmGenerational)
6564-
{
6565-
//Can release asap
6566-
((unsigned char *)inData)[HX_ENDIAN_MARK_ID_BYTE] = 0;
6567-
}
6568-
#endif
6618+
InternalReleaseMem(inData);
65696619

65706620
return new_data;
65716621
}

test/haxe/TestStringHash.hx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ class TestStringHash extends haxe.unit.TestCase
3434
values[idxInt] = j;
3535
}
3636
}
37+
var arr = [0,1,2];
3738
var keys = h.keys();
39+
// Empty allocations can mess with the GC nursery
40+
cpp.NativeArray.setSize(arr,0);
41+
cpp.NativeArray.setSize(arr,3);
3842
var keyed = new Array<Bool>();
3943
for(i in 0...values.length)
4044
keyed[i] = false;

0 commit comments

Comments
 (0)