Skip to content

Commit d07045f

Browse files
committed
[MERGE #1635 @leirocks] fix xProc number allocator
Merge pull request #1635 from leirocks:xprocnumber - some fix needed because of the IDL adjustment(numberSegment changing to pointer and Arena allocated) - delay allocate the segment only when necessary(when there's number need to be allocated in JIT time) - added test switch to make the integration and segment full code path easier to test in oop JIT (currently 0x20 pages hold 0x2000 numbers which is extremely hard to fullfil the segment) - make recycler memory verify work for cross process number allocator
2 parents b45e179 + ecfe189 commit d07045f

16 files changed

+331
-111
lines changed

lib/Backend/CodeGenNumberAllocator.cpp

Lines changed: 120 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//-------------------------------------------------------------------------------------------------------
55
#include "Backend.h"
66

7-
7+
#if !FLOATVAR
88
CodeGenNumberThreadAllocator::CodeGenNumberThreadAllocator(Recycler * recycler)
99
: recycler(recycler), currentNumberSegment(nullptr), currentChunkSegment(nullptr),
1010
numberSegmentEnd(nullptr), currentNumberBlockEnd(nullptr), nextNumber(nullptr), chunkSegmentEnd(nullptr),
@@ -245,7 +245,6 @@ CodeGenNumberAllocator::CodeGenNumberAllocator(CodeGenNumberThreadAllocator * th
245245
}
246246

247247
// We should never call this function if we are using tagged float
248-
#if !FLOATVAR
249248
Js::JavascriptNumber *
250249
CodeGenNumberAllocator::Alloc()
251250
{
@@ -274,7 +273,7 @@ CodeGenNumberAllocator::Alloc()
274273
this->chunkTail->numbers[this->currentChunkNumberCount++] = newNumber;
275274
return newNumber;
276275
}
277-
#endif
276+
278277

279278
CodeGenNumberChunk *
280279
CodeGenNumberAllocator::Finalize()
@@ -290,16 +289,12 @@ CodeGenNumberAllocator::Finalize()
290289
return finalizedChunk;
291290
}
292291

293-
/* static */
294-
uint
295-
XProcNumberPageSegmentImpl::GetSizeCat()
296-
{
297-
return (uint)HeapInfo::GetAlignedSizeNoCheck(sizeof(Js::JavascriptNumber));
298-
}
299-
300292

301-
Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess, double value, Js::StaticType* numberTypeStatic, void* javascriptNumberVtbl)
293+
uint XProcNumberPageSegmentImpl::sizeCat = sizeof(Js::JavascriptNumber);
294+
Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(Func* func, double value)
302295
{
296+
HANDLE hProcess = func->GetThreadContextInfo()->GetProcessHandle();
297+
303298
XProcNumberPageSegmentImpl* tail = this;
304299

305300
if (this->pageAddress != 0)
@@ -309,39 +304,54 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess
309304
tail = (XProcNumberPageSegmentImpl*)tail->nextSegment;
310305
}
311306

312-
if (tail->pageAddress + tail->committedEnd - tail->allocEndAddress >= GetSizeCat())
307+
if (tail->pageAddress + tail->committedEnd - tail->allocEndAddress >= sizeCat)
313308
{
314309
auto number = tail->allocEndAddress;
315-
tail->allocEndAddress += GetSizeCat();
310+
tail->allocEndAddress += sizeCat;
316311

317-
Js::JavascriptNumber localNumber(value, numberTypeStatic
318312
#if DBG
319-
, true
313+
Js::JavascriptNumber localNumber(value, (Js::StaticType*)func->GetScriptContextInfo()->GetNumberTypeStaticAddr(), true);
314+
#else
315+
Js::JavascriptNumber localNumber(value, (Js::StaticType*)func->GetScriptContextInfo()->GetNumberTypeStaticAddr());
320316
#endif
321-
);
317+
Js::JavascriptNumber* pLocalNumber = &localNumber;
322318

319+
#ifdef RECYCLER_MEMORY_VERIFY
320+
if (func->GetScriptContextInfo()->IsRecyclerVerifyEnabled())
321+
{
322+
pLocalNumber = (Js::JavascriptNumber*)alloca(sizeCat);
323+
memset(pLocalNumber, Recycler::VerifyMemFill, sizeCat);
324+
Recycler::FillPadNoCheck(pLocalNumber, sizeof(Js::JavascriptNumber), sizeCat, false);
325+
pLocalNumber = new (pLocalNumber) Js::JavascriptNumber(localNumber);
326+
}
327+
#endif
323328
// change vtable to the remote one
324-
*(void**)&localNumber = javascriptNumberVtbl;
329+
*(void**)pLocalNumber = (void*)func->GetScriptContextInfo()->GetVTableAddress(VTableValue::VtableJavascriptNumber);
325330

326331
// initialize number by WriteProcessMemory
327332
SIZE_T bytesWritten;
328-
WriteProcessMemory(hProcess, (void*)number, &localNumber, sizeof(localNumber), &bytesWritten);
333+
if (!WriteProcessMemory(hProcess, (void*)number, pLocalNumber, sizeCat, &bytesWritten)
334+
|| bytesWritten != sizeCat)
335+
{
336+
Output::Print(_u("FATAL ERROR: WriteProcessMemory failed, GLE: %d\n"), GetLastError());
337+
Js::Throw::FatalInternalError(); // TODO: don't bring down whole server process, but pass the last error to main process
338+
}
329339

330340
return (Js::JavascriptNumber*) number;
331341
}
332342

333343
// alloc blocks
334-
if ((void*)tail->committedEnd < tail->GetEndAddress())
344+
if (tail->GetCommitEndAddress() < tail->GetEndAddress())
335345
{
336-
Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->committedEnd) >= BlockSize);
346+
Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->GetCommitEndAddress()) >= BlockSize);
337347
// TODO: implement guard pages (still necessary for OOP JIT?)
338348
auto ret = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), BlockSize, MEM_COMMIT, PAGE_READWRITE);
339349
if (!ret)
340350
{
341351
Js::Throw::OutOfMemory();
342352
}
343353
tail->committedEnd += BlockSize;
344-
return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
354+
return AllocateNumber(func, value);
345355
}
346356
}
347357

@@ -354,12 +364,11 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess
354364

355365
if (tail->pageAddress == 0)
356366
{
357-
tail = new (tail) XProcNumberPageSegmentImpl();
358367
tail->pageAddress = (intptr_t)pages;
359368
tail->allocStartAddress = this->pageAddress;
360369
tail->allocEndAddress = this->pageAddress;
361370
tail->nextSegment = nullptr;
362-
return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
371+
return AllocateNumber(func, value);
363372
}
364373
else
365374
{
@@ -370,15 +379,40 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess
370379
}
371380
seg = new (seg) XProcNumberPageSegmentImpl();
372381
tail->nextSegment = seg;
373-
return seg->AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
382+
return seg->AllocateNumber(func, value);
374383
}
375384
}
376385

377386

378387
XProcNumberPageSegmentImpl::XProcNumberPageSegmentImpl()
379388
{
380-
this->blockIntegratedSize = 0;
381-
this->pageSegment = 0;
389+
memset(this, 0, sizeof(XProcNumberPageSegment));
390+
}
391+
392+
void XProcNumberPageSegmentImpl::Initialize(bool recyclerVerifyEnabled, uint recyclerVerifyPad)
393+
{
394+
size_t allocSize = sizeof(Js::JavascriptNumber);
395+
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
396+
allocSize += Js::Configuration::Global.flags.NumberAllocPlusSize;
397+
#endif
398+
#ifdef RECYCLER_MEMORY_VERIFY
399+
// TODO: share same pad size with main process
400+
if (recyclerVerifyEnabled)
401+
{
402+
size_t padAllocSize = AllocSizeMath::Add(sizeof(Js::JavascriptNumber) + sizeof(size_t), recyclerVerifyPad);
403+
allocSize = padAllocSize < allocSize ? allocSize : padAllocSize;
404+
}
405+
#endif
406+
407+
allocSize = (uint)HeapInfo::GetAlignedSizeNoCheck(allocSize);
408+
409+
if (BlockSize%allocSize != 0)
410+
{
411+
// align allocation sizeCat to be 2^n to make integration easier
412+
allocSize = BlockSize / (1 << (Math::Log2(BlockSize / allocSize)));
413+
}
414+
415+
sizeCat = allocSize;
382416
}
383417

384418
Js::JavascriptNumber** ::XProcNumberPageSegmentManager::RegisterSegments(XProcNumberPageSegment* segments)
@@ -390,7 +424,7 @@ Js::JavascriptNumber** ::XProcNumberPageSegmentManager::RegisterSegments(XProcNu
390424
size_t totalCount = 0;
391425
while (temp)
392426
{
393-
totalCount += (temp->allocEndAddress - temp->allocStartAddress) / XProcNumberPageSegmentImpl::GetSizeCat();
427+
totalCount += (temp->allocEndAddress - temp->allocStartAddress) / XProcNumberPageSegmentImpl::sizeCat;
394428
temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
395429
}
396430

@@ -400,18 +434,15 @@ Js::JavascriptNumber** ::XProcNumberPageSegmentManager::RegisterSegments(XProcNu
400434
int count = 0;
401435
while (temp)
402436
{
403-
auto start = temp->allocStartAddress;
404-
while (start < temp->allocEndAddress)
437+
while (temp->allocStartAddress < temp->allocEndAddress)
405438
{
406-
numbers[count] = (Js::JavascriptNumber*)start;
439+
numbers[count] = (Js::JavascriptNumber*)temp->allocStartAddress;
407440
count++;
408-
start += XProcNumberPageSegmentImpl::GetSizeCat();
441+
temp->allocStartAddress += XProcNumberPageSegmentImpl::sizeCat;
409442
}
410443
temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
411444
}
412445

413-
414-
415446
AutoCriticalSection autoCS(&cs);
416447
if (this->segmentsList == nullptr)
417448
{
@@ -430,16 +461,10 @@ Js::JavascriptNumber** ::XProcNumberPageSegmentManager::RegisterSegments(XProcNu
430461
return numbers;
431462
}
432463

433-
void XProcNumberPageSegmentManager::GetFreeSegment(XProcNumberPageSegment * seg)
464+
XProcNumberPageSegment * XProcNumberPageSegmentManager::GetFreeSegment(Memory::ArenaAllocator* alloc)
434465
{
435466
AutoCriticalSection autoCS(&cs);
436467

437-
if (segmentsList == nullptr)
438-
{
439-
new (seg) XProcNumberPageSegmentImpl();
440-
return;
441-
}
442-
443468
auto temp = segmentsList;
444469
auto prev = &segmentsList;
445470
while (temp)
@@ -449,13 +474,17 @@ void XProcNumberPageSegmentManager::GetFreeSegment(XProcNumberPageSegment * seg)
449474
*prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
450475

451476
// remove from the list
452-
memcpy(seg, temp, sizeof(XProcNumberPageSegment));
477+
XProcNumberPageSegment * seg = (XProcNumberPageSegment *)AnewStructZ(alloc, XProcNumberPageSegmentImpl);
478+
temp->nextSegment = 0;
479+
memcpy(seg, temp, sizeof(XProcNumberPageSegment));
453480
midl_user_free(temp);
454-
return;
481+
return seg;
455482
}
456483
prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
457484
temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
458485
}
486+
487+
return nullptr;
459488
}
460489

461490
void XProcNumberPageSegmentManager::Integrate()
@@ -466,36 +495,62 @@ void XProcNumberPageSegmentManager::Integrate()
466495
auto prev = &this->segmentsList;
467496
while (temp)
468497
{
469-
if (temp->pageSegment == 0)
470-
{
471-
auto leafPageAllocator = recycler->GetRecyclerLeafPageAllocator();
472-
DListBase<PageSegment> segmentList;
473-
temp->pageSegment = (intptr_t)leafPageAllocator->AllocPageSegment(segmentList, leafPageAllocator,
474-
(void*)temp->pageAddress, XProcNumberPageSegmentImpl::PageCount, temp->committedEnd / AutoSystemInfo::PageSize);
475-
leafPageAllocator->IntegrateSegments(segmentList, 1, XProcNumberPageSegmentImpl::PageCount);
476-
477-
this->integratedSegmentCount++;
478-
}
479-
480-
unsigned int minIntegrateSize = XProcNumberPageSegmentImpl::BlockSize;
481-
for (; temp->pageAddress + temp->blockIntegratedSize + minIntegrateSize < (unsigned int)temp->allocEndAddress;
482-
temp->blockIntegratedSize += minIntegrateSize)
498+
if((uintptr_t)temp->allocEndAddress - (uintptr_t)temp->pageAddress > temp->blockIntegratedSize + XProcNumberPageSegmentImpl::BlockSize)
483499
{
484-
TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
500+
if (temp->pageSegment == 0)
501+
{
502+
auto leafPageAllocator = recycler->GetRecyclerLeafPageAllocator();
503+
DListBase<PageSegment> segmentList;
504+
temp->pageSegment = (intptr_t)leafPageAllocator->AllocPageSegment(segmentList, leafPageAllocator,
505+
(void*)temp->pageAddress, XProcNumberPageSegmentImpl::PageCount, temp->committedEnd / AutoSystemInfo::PageSize);
506+
507+
if (temp->pageSegment)
508+
{
509+
leafPageAllocator->IntegrateSegments(segmentList, 1, XProcNumberPageSegmentImpl::PageCount);
510+
this->integratedSegmentCount++;
511+
}
512+
}
485513

486-
if (!recycler->IntegrateBlock<LeafBit>((char*)temp->pageAddress + temp->blockIntegratedSize,
487-
(PageSegment*)temp->pageSegment, XProcNumberPageSegmentImpl::GetSizeCat(), sizeof(Js::JavascriptNumber)))
514+
if (temp->pageSegment)
488515
{
489-
Js::Throw::OutOfMemory();
516+
unsigned int minIntegrateSize = XProcNumberPageSegmentImpl::BlockSize;
517+
for (; temp->pageAddress + temp->blockIntegratedSize + minIntegrateSize < (unsigned int)temp->allocEndAddress;
518+
temp->blockIntegratedSize += minIntegrateSize)
519+
{
520+
TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
521+
522+
if (!recycler->IntegrateBlock<LeafBit>((char*)temp->pageAddress + temp->blockIntegratedSize,
523+
(PageSegment*)temp->pageSegment, XProcNumberPageSegmentImpl::sizeCat, sizeof(Js::JavascriptNumber)))
524+
{
525+
Js::Throw::OutOfMemory();
526+
}
527+
}
528+
529+
if ((uintptr_t)temp->allocEndAddress + XProcNumberPageSegmentImpl::sizeCat
530+
> (uintptr_t)temp->pageAddress + XProcNumberPageSegmentImpl::PageCount*AutoSystemInfo::PageSize)
531+
{
532+
*prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
533+
midl_user_free(temp);
534+
temp = *prev;
535+
continue;
536+
}
490537
}
491538
}
492539

493-
*prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
494-
midl_user_free(temp);
495-
temp = *prev;
540+
temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
496541
}
497542
}
498543

544+
XProcNumberPageSegmentManager::XProcNumberPageSegmentManager(Recycler* recycler)
545+
:segmentsList(nullptr), recycler(recycler), integratedSegmentCount(0)
546+
{
547+
#ifdef RECYCLER_MEMORY_VERIFY
548+
XProcNumberPageSegmentImpl::Initialize(recycler->VerifyEnabled() == TRUE, recycler->GetVerifyPad());
549+
#else
550+
XProcNumberPageSegmentImpl::Initialize(false, 0);
551+
#endif
552+
}
553+
499554
XProcNumberPageSegmentManager::~XProcNumberPageSegmentManager()
500555
{
501556
auto temp = segmentsList;
@@ -505,4 +560,5 @@ XProcNumberPageSegmentManager::~XProcNumberPageSegmentManager()
505560
midl_user_free(temp);
506561
temp = (XProcNumberPageSegmentImpl*)next;
507562
}
508-
}
563+
}
564+
#endif

lib/Backend/CodeGenNumberAllocator.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//-------------------------------------------------------------------------------------------------------
55
#pragma once
66

7+
#if !FLOATVAR
78
/****************************************************************************
89
* CodeGenNumberThreadAllocator
910
*
@@ -157,14 +158,15 @@ namespace Js
157158
struct XProcNumberPageSegmentImpl : public XProcNumberPageSegment
158159
{
159160
XProcNumberPageSegmentImpl();
160-
Js::JavascriptNumber* AllocateNumber(HANDLE hProcess, double value, Js::StaticType* numberTypeStatic, void* javascriptNumberVtbl);
161+
Js::JavascriptNumber* AllocateNumber(Func* func, double value);
161162
unsigned int GetTotalSize() { return PageCount * AutoSystemInfo::PageSize; }
162163
void* GetEndAddress() { return (void*)(this->pageAddress + PageCount * AutoSystemInfo::PageSize); }
163164
void* GetCommitEndAddress() { return (void*)(this->pageAddress + this->committedEnd); }
164165

165166
static const uint BlockSize = SmallAllocationBlockAttributes::PageCount*AutoSystemInfo::PageSize;
166167
static const uint PageCount = Memory::IdleDecommitPageAllocator::DefaultMaxAllocPageCount;
167-
static uint GetSizeCat();
168+
static uint sizeCat;
169+
static void Initialize(bool recyclerVerifyEnabled, uint recyclerVerifyPad);
168170
};
169171

170172
static_assert(sizeof(XProcNumberPageSegmentImpl) == sizeof(XProcNumberPageSegment), "should not have data member in XProcNumberPageSegmentImpl");
@@ -175,16 +177,13 @@ struct XProcNumberPageSegmentManager
175177
XProcNumberPageSegmentImpl* segmentsList;
176178
Recycler* recycler;
177179
unsigned int integratedSegmentCount;
178-
XProcNumberPageSegmentManager(Recycler* recycler)
179-
:segmentsList(nullptr), recycler(recycler), integratedSegmentCount(0)
180-
{
181-
}
180+
XProcNumberPageSegmentManager(Recycler* recycler);
182181

183182
~XProcNumberPageSegmentManager();
184183

185-
void GetFreeSegment(XProcNumberPageSegment * seg);
184+
XProcNumberPageSegment * GetFreeSegment(Memory::ArenaAllocator* alloc);
186185
Js::JavascriptNumber** RegisterSegments(XProcNumberPageSegment* segments);
187186

188187
void Integrate();
189188
};
190-
189+
#endif

0 commit comments

Comments
 (0)