Przeglądaj źródła

implement NumberAllocator for OOP JIT

     Allocate pages in JIT process with VirtualAllocEx. Initially reserve 0x20 pages(required by recycler leaf page allocator), then commit 2 pages (small block) incrementally.
     Main process send over the available page through RPC, JIT process will use the free part of the page before committing new pages.
     Number chunks are allocated after JIT is done, use same allocating mechanism as in-proc JIT
     The pageSegment is created when integrating to recycler page allocator
Lei Shi 9 lat temu
rodzic
commit
bd86f137c3

+ 234 - 0
lib/Backend/CodeGenNumberAllocator.cpp

@@ -211,6 +211,8 @@ CodeGenNumberThreadAllocator::Integrate()
 
     while (!pendingIntegrationChunkBlock.Empty())
     {
+        // REVIEW: the above number block integration can be moved into this loop
+
         TRACK_ALLOC_INFO(recycler, CodeGenNumberChunk, Recycler, 0, (size_t)-1);
 
         BlockRecord& record = pendingIntegrationChunkBlock.Head();
@@ -287,3 +289,235 @@ CodeGenNumberAllocator::Finalize()
     this->currentChunkNumberCount = 0;
     return finalizedChunk;
 }
+
+
+Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess, double value, Js::StaticType* numberTypeStatic, void* javascriptNumberVtbl)
+{
+    XProcNumberPageSegmentImpl* tail = this;
+
+    if (this->pageAddress != 0)
+    {
+        while (tail->nextSegment)
+        {
+            tail = (XProcNumberPageSegmentImpl*)tail->nextSegment;
+        }
+
+        if (tail->pageAddress + tail->committedEnd - tail->allocEndAddress >= sizeCat)
+        {
+            auto number = tail->allocEndAddress;
+            tail->allocEndAddress += sizeCat;
+
+            Js::JavascriptNumber localNumber(value, numberTypeStatic, true);
+
+            // change vtable to the remote one
+            *(void**)&localNumber = javascriptNumberVtbl;
+
+            // initialize number by WriteProcessMemory
+            SIZE_T bytesWritten;
+            WriteProcessMemory(hProcess, (void*)number, &localNumber, sizeof(localNumber), &bytesWritten);
+
+            return (Js::JavascriptNumber*) number;
+        }
+
+        // alloc blocks
+        if ((void*)tail->committedEnd < tail->GetEndAddress())
+        {
+            Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->committedEnd) >= tail->blockSize);
+            // TODO: implement guard pages (still necessary for OOP JIT?)
+            auto ret = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), tail->blockSize, MEM_COMMIT, PAGE_READWRITE);
+            if (!ret)
+            {
+                Js::Throw::OutOfMemory();
+            }
+            tail->committedEnd += tail->blockSize;
+            return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
+        }
+    }
+
+    // alloc new segment
+    void* pages = ::VirtualAllocEx(hProcess, nullptr, this->pageCount * AutoSystemInfo::PageSize, MEM_RESERVE, PAGE_READWRITE);
+    if (pages == nullptr)
+    {
+        Js::Throw::OutOfMemory();
+    }
+
+    if (tail->pageAddress == 0)
+    {
+        tail = new (tail) XProcNumberPageSegmentImpl();
+        tail->pageAddress = (int)pages;
+        tail->allocStartAddress = this->pageAddress;
+        tail->allocEndAddress = this->pageAddress;
+        tail->nextSegment = nullptr;
+        return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
+    }
+    else
+    {
+        XProcNumberPageSegmentImpl* seg = new (midl_user_allocate(sizeof(XProcNumberPageSegment))) XProcNumberPageSegmentImpl();
+        tail->nextSegment = seg;
+        return seg->AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
+    }
+}
+
+
+XProcNumberPageSegmentImpl::XProcNumberPageSegmentImpl()
+{
+    this->pageCount = Memory::IdleDecommitPageAllocator::DefaultMaxAllocPageCount;
+    this->sizeCat = HeapInfo::GetAlignedSizeNoCheck(sizeof(Js::JavascriptNumber));
+    this->blockSize = SmallAllocationBlockAttributes::PageCount*AutoSystemInfo::PageSize;
+    this->blockIntegratedSize = 0;
+    this->pageSegment = 0;
+}
+
+CodeGenNumberChunk* ::XProcNumberPageSegmentManager::RegisterSegments(XProcNumberPageSegment* segments)
+{
+    Assert(segments->pageAddress && segments->allocStartAddress && segments->allocEndAddress);
+
+
+    XProcNumberPageSegmentImpl* segmentImpl = (XProcNumberPageSegmentImpl*)segments;
+
+    auto temp = segmentImpl;
+    CodeGenNumberChunk* chunk = nullptr;
+    int numberCount = CodeGenNumberChunk::MaxNumberCount;
+    while (temp)
+    {
+        auto start = temp->allocStartAddress;
+
+        if (temp->GetChunkAllocator() == nullptr)
+        {
+            temp->chunkAllocator = (intptr_t)HeapNew(CodeGenNumberThreadAllocator, this->recycler);
+        }
+
+        while (start < temp->allocEndAddress)
+        {
+            if (numberCount == CodeGenNumberChunk::MaxNumberCount)
+            {
+                auto newChunk = temp->GetChunkAllocator()->AllocChunk();
+                newChunk->next = chunk;
+                chunk = newChunk;
+                numberCount = 0;
+            }
+            chunk->numbers[numberCount++] = (Js::JavascriptNumber*)start;
+            start += temp->sizeCat;
+        }
+
+        temp->GetChunkAllocator()->FlushAllocations();
+
+        temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+    }
+
+    AutoCriticalSection autoCS(&cs);
+    if (this->segmentsList == nullptr)
+    {
+        this->segmentsList = segmentImpl;
+    }
+    else
+    {
+        auto temp = segmentsList;
+        while (temp->nextSegment)
+        {
+            temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+        }
+        temp->nextSegment = segmentImpl;
+    }
+
+    return chunk;
+}
+
+void XProcNumberPageSegmentManager::GetFreeSegment(XProcNumberPageSegment& seg)
+{
+    AutoCriticalSection autoCS(&cs);
+
+    memset(&seg, 0, sizeof(seg));
+
+    if (segmentsList == nullptr)
+    {
+        new (&seg) XProcNumberPageSegmentImpl();
+        return;
+    }
+
+    auto temp = segmentsList;
+    auto prev = &segmentsList;
+    while (temp)
+    {
+        if (temp->allocEndAddress != temp->pageAddress + (int)(temp->pageCount*AutoSystemInfo::PageSize)) // not full
+        {
+            *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+
+            // remove from the list
+            memcpy(&seg, temp, sizeof(seg));
+            midl_user_free(temp);
+            return;
+        }
+        prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
+        temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+    }
+}
+
+void XProcNumberPageSegmentManager::Integrate()
+{
+    AutoCriticalSection autoCS(&cs);
+
+    auto temp = this->segmentsList;
+    auto prev = &this->segmentsList;
+    while (temp)
+    {
+        if (temp->pageSegment == 0)
+        {
+            auto leafPageAllocator = recycler->GetRecyclerLeafPageAllocator();
+            DListBase<PageSegment> segmentList;
+            temp->pageSegment = (intptr_t)leafPageAllocator->AllocPageSegment(segmentList, leafPageAllocator,
+                (void*)temp->pageAddress, temp->pageCount, temp->committedEnd / AutoSystemInfo::PageSize);
+            leafPageAllocator->IntegrateSegments(segmentList, 1, temp->pageCount);
+
+            this->integratedSegmentCount++;
+        }
+
+        if (!temp->GetChunkAllocator()->pendingIntegrationChunkBlock.Empty())
+        {
+            Assert(sizeof(CodeGenNumberChunk) == sizeof(Js::JavascriptNumber));
+            size_t minIntegrateSize = temp->blockSize*CodeGenNumberChunk::MaxNumberCount;
+            for (; temp->pageAddress + temp->blockIntegratedSize + minIntegrateSize < (unsigned int)temp->allocEndAddress;
+                temp->blockIntegratedSize += minIntegrateSize)
+            {
+                TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
+
+                if (!recycler->IntegrateBlock<LeafBit>((char*)temp->pageAddress + temp->blockIntegratedSize, (PageSegment*)temp->pageSegment, temp->sizeCat, sizeof(Js::JavascriptNumber)))
+                {
+                    Js::Throw::OutOfMemory();
+                }
+            }
+        }
+
+        temp->GetChunkAllocator()->Integrate();
+
+        if (temp->blockIntegratedSize >= temp->pageCount*AutoSystemInfo::PageSize)
+        {
+            // all pages are integrated, don't need this segment any more
+            *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+            HeapDelete(temp->GetChunkAllocator());
+            midl_user_free(temp);
+            temp = *prev;
+        }
+        else
+        {
+            prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
+            temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
+        }
+
+    }
+}
+
+XProcNumberPageSegmentManager::~XProcNumberPageSegmentManager()
+{
+    auto temp = segmentsList;
+    while (temp)
+    {
+        auto next = temp->nextSegment;
+        if (temp->chunkAllocator)
+        {
+            HeapDelete((CodeGenNumberThreadAllocator*)temp->chunkAllocator);
+        }
+        midl_user_free(temp);
+        temp = (XProcNumberPageSegmentImpl*)next;
+    }
+}

+ 39 - 0
lib/Backend/CodeGenNumberAllocator.h

@@ -63,6 +63,7 @@ CompileAssert(
 
 class CodeGenNumberThreadAllocator
 {
+    friend struct XProcNumberPageSegmentManager;
 public:
     CodeGenNumberThreadAllocator(Recycler * recycler);
     ~CodeGenNumberThreadAllocator();
@@ -144,3 +145,41 @@ private:
     bool finalized;
 #endif
 };
+
+namespace Js
+{
+    class StaticType;
+}
+
+struct XProcNumberPageSegmentImpl : public XProcNumberPageSegment
+{
+    XProcNumberPageSegmentImpl();
+    Js::JavascriptNumber* AllocateNumber(HANDLE hProcess, double value, Js::StaticType* numberTypeStatic, void* javascriptNumberVtbl);
+    unsigned int GetTotalSize() { return this->pageCount * AutoSystemInfo::PageSize; }
+    void* GetEndAddress() { return (void*)(this->pageAddress + this->pageCount * AutoSystemInfo::PageSize); }
+    void* GetCommitEndAddress() { return (void*)(this->pageAddress + this->committedEnd); }
+    // TODO: using CodeGenNumberThreadAllocator to allocate the chunks only, abstract chunk alloc code out of CodeGenNumberThreadAllocator
+    CodeGenNumberThreadAllocator* GetChunkAllocator() { return (CodeGenNumberThreadAllocator*) this->chunkAllocator; }
+};
+
+static_assert(sizeof(XProcNumberPageSegmentImpl) == sizeof(XProcNumberPageSegment), "should not have data member in XProcNumberPageSegmentImpl");
+
+struct XProcNumberPageSegmentManager
+{
+    CriticalSection cs;
+    XProcNumberPageSegmentImpl* segmentsList;
+    Recycler* recycler;
+    unsigned int integratedSegmentCount;
+    XProcNumberPageSegmentManager(Recycler* recycler)
+        :segmentsList(nullptr), recycler(recycler), integratedSegmentCount(0)
+    {
+    }
+
+    ~XProcNumberPageSegmentManager();
+
+    void GetFreeSegment(XProcNumberPageSegment& seg);
+    CodeGenNumberChunk* RegisterSegments(XProcNumberPageSegment* segments);
+
+    void Integrate();
+};
+

+ 1 - 1
lib/Backend/Encoder.cpp

@@ -312,7 +312,7 @@ Encoder::Encode()
     {
 
         // TODO: OOP JIT, inlinee frame map
-        if (false) // in-proc JIT
+        if (!m_func->IsOOPJIT()) // in-proc JIT
         {
             entryPointInfo->RecordInlineeFrameMap(m_inlineeFrameMap);
         }

+ 9 - 0
lib/Backend/Func.cpp

@@ -1505,6 +1505,15 @@ Func::GetFunctionEntryInsertionPoint()
     return insertInsert->m_next;
 }
 
+Js::JavascriptNumber* 
+Func::AllocateOOPNumber(double value)
+{
+    return this->GetXProcNumberAllocator()->AllocateNumber(this->GetThreadContextInfo()->GetProcessHandle(), 
+        value, 
+        (Js::StaticType*)this->GetScriptContextInfo()->GetNumberTypeStaticAddr(),
+        (void*)this->GetScriptContextInfo()->GetVTableAddress(VTableValue::VtableJavascriptNumber));
+}
+
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
 void
 Func::DumpFullFunctionName()

+ 8 - 0
lib/Backend/Func.h

@@ -100,6 +100,10 @@ public:
     {
         return &this->m_codeGenAllocators->emitBufferManager;
     }
+    XProcNumberPageSegmentImpl* GetXProcNumberAllocator()
+    {
+        return (XProcNumberPageSegmentImpl*)this->GetJITOutput()->GetOutputData()->numberPageSegments;
+    }
 
     Js::ScriptContextProfiler *GetCodeGenProfiler() const
     {
@@ -110,6 +114,8 @@ public:
 #endif
     }
 
+    bool IsOOPJIT() { return true; }
+
     void InitLocalClosureSyms();
 
     bool HasAnyStackNestedFunc() const { return this->hasAnyStackNestedFunc; }
@@ -435,6 +441,8 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
         return this->isTJLoopBody;
     }
 
+    Js::JavascriptNumber* AllocateOOPNumber(double value);
+
     Js::ObjTypeSpecFldInfo* GetObjTypeSpecFldInfo(const uint index) const;
     Js::ObjTypeSpecFldInfo* GetGlobalObjTypeSpecFldInfo(uint propertyInfoId) const;
     void SetGlobalObjTypeSpecFldInfo(uint propertyInfoId, Js::ObjTypeSpecFldInfo* info);

+ 1 - 1
lib/Backend/IR.cpp

@@ -3439,7 +3439,7 @@ IR::Instr* IR::Instr::NewConstantLoad(IR::RegOpnd* dstOpnd, intptr_t varConst, J
             {
                 // TODO (michhol): OOP JIT. we may need to unbox before sending over const table                
 
-                if (false)
+                if (!func->IsOOPJIT())
                 {
                     srcOpnd = IR::FloatConstOpnd::New((Js::Var)varConst, TyFloat64, func);
                 }

+ 17 - 3
lib/Backend/InlineeFrameInfo.cpp

@@ -42,15 +42,29 @@ Js::Var BailoutConstantValue::ToVar(Func* func, Js::ScriptContext* scriptContext
     }
     else if (this->type == TyFloat64)
     {
-        varValue = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)this->u.floatConst.value, scriptContext);
+        if (!func->IsOOPJIT()) // in-proc jit
+        {
+            varValue = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)this->u.floatConst.value, scriptContext);
+        }
+        else // OOP JIT
+        {
+            varValue = func->AllocateOOPNumber((double)this->u.floatConst.value);
+        }
     }
     else if (IRType_IsSignedInt(this->type) && TySize[this->type] <= 4 && !Js::TaggedInt::IsOverflow((int32)this->u.intConst.value))
     {
         varValue = Js::TaggedInt::ToVarUnchecked((int32)this->u.intConst.value);
     }
     else
-    {
-        varValue = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)this->u.intConst.value, scriptContext);
+    {       
+        if (!func->IsOOPJIT()) // in-proc jit
+        {
+            varValue = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)this->u.intConst.value, scriptContext);
+        }
+        else // OOP JIT
+        {
+            varValue = func->AllocateOOPNumber((double)this->u.intConst.value);
+        }
     }
     return varValue;
 

+ 1 - 1
lib/Backend/LowerMDShared.cpp

@@ -6997,7 +6997,7 @@ LowererMD::LoadFloatValue(IR::Opnd * opndDst, double value, IR::Instr * instrIns
         pValue = NativeCodeDataNew(instrInsert->m_func->GetNativeCodeDataAllocator(), float, (float)value);
     }
 
-    if (false)
+    if (!instrInsert->m_func->IsOOPJIT())
     {
         opnd = IR::MemRefOpnd::New((void*)pValue, isFloat64 ? TyMachDouble : TyFloat32,
             instrInsert->m_func, isFloat64 ? IR::AddrOpndKindDynamicDoubleRef : IR::AddrOpndKindDynamicFloatRef);

+ 17 - 0
lib/Backend/NativeCodeGenerator.cpp

@@ -884,6 +884,8 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
             }
             JITOutputData jitWriteData = {0};
 
+            threadContext->GetXProcNumberPageSegmentManager()->GetFreeSegment(workItem->GetJITData()->xProcNumberPageSegment);
+
             HRESULT hr = scriptContext->GetThreadContext()->m_codeGenManager.RemoteCodeGenCall(
                 workItem->GetJITData(),
                 scriptContext->GetThreadContext()->GetRemoteThreadContextAddr(),
@@ -896,6 +898,21 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
 
             workItem->GetFunctionBody()->SetFrameHeight(workItem->GetEntryPoint(), jitWriteData.writeableEPData.frameHeight);
 
+            if (jitWriteData.numberPageSegments)
+            {
+                if (jitWriteData.numberPageSegments->pageAddress == 0)
+                {
+                    midl_user_free(jitWriteData.numberPageSegments);
+                    jitWriteData.numberPageSegments = nullptr;
+                }
+                else
+                {
+                    // TODO: when codegen fail, need to return the segment as well
+                    auto numberChunks = threadContext->GetXProcNumberPageSegmentManager()->RegisterSegments(jitWriteData.numberPageSegments);
+                    epInfo->SetNumberChunks(numberChunks);
+                }
+            }
+
             if (jitWriteData.nativeDataFixupTable)
             {
                 for (unsigned int i = 0; i < jitWriteData.nativeDataFixupTable->count; i++)

+ 31 - 4
lib/Backend/Opnd.cpp

@@ -1589,7 +1589,7 @@ FloatConstOpnd::GetAddrOpnd(Func *func, bool dontEncode)
 #if !FLOATVAR
     if (this->m_number)
     {
-        if (false) // in-proc JIT
+        if (!func->IsOOPJIT()) // in-proc JIT
         {
             return AddrOpnd::New(this->m_number, (Js::TaggedNumber::Is(this->m_number) ? AddrOpndKindConstantVar : AddrOpndKindDynamicVar), func, dontEncode);
         }
@@ -1932,7 +1932,16 @@ AddrOpnd::NewFromNumber(int32 value, Func *func, bool dontEncode /* = false */)
     }
     else
     {
-        Js::Var number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+        Js::Var number = nullptr;
+        if (!func->IsOOPJIT()) // in-proc jit
+        {
+            number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+        }
+        else // OOP JIT
+        {
+            number = func->AllocateOOPNumber((double)value);
+        }
+
         return New(number, AddrOpndKindDynamicVar, func, dontEncode);
     }
 }
@@ -1946,7 +1955,16 @@ AddrOpnd::NewFromNumber(int64 value, Func *func, bool dontEncode /* = false */)
     }
     else
     {
-        Js::Var number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+        Js::Var number = nullptr;
+        if (!func->IsOOPJIT()) // in-proc jit
+        {
+            number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+        }
+        else // OOP JIT
+        {
+            number = func->AllocateOOPNumber((double)value);
+        }
+
         return New(number, AddrOpndKindDynamicVar, func, dontEncode);
     }
 }
@@ -1984,7 +2002,16 @@ AddrOpnd::NewFromNumber(double value, Func *func, bool dontEncode /* = false */)
         return New(Js::TaggedInt::ToVarUnchecked(nValue), AddrOpndKindConstantVar, func, dontEncode);
     }
 
-    Js::Var number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+    Js::Var number = nullptr;
+    if (!func->IsOOPJIT()) // in-proc jit
+    {
+        number = Js::JavascriptNumber::NewCodeGenInstance(func->GetNumberAllocator(), (double)value, func->GetScriptContext());
+    }
+    else // OOP JIT
+    {
+        number = func->AllocateOOPNumber((double)value);
+    }
+
     return New(number, AddrOpndKindDynamicVar, func, dontEncode);
 }
 

+ 1 - 1
lib/Backend/amd64/LinearScanMD.cpp

@@ -264,7 +264,7 @@ LinearScanMD::GenerateBailOut(IR::Instr * instr, __in_ecount(registerSaveSymsCou
     }
 
 
-    if (false)
+    if (!func->IsOOPJIT())
     {
         // Pass in the bailout record
         //     mov  rcx, bailOutRecord

+ 1 - 1
lib/Backend/i386/LinearScanMD.cpp

@@ -117,7 +117,7 @@ LinearScanMD::GenerateBailOut(IR::Instr * instr, __in_ecount(registerSaveSymsCou
     // Pass in the bailout record
     //     push bailOutRecord
     {
-        if (false) // in-proc jit
+        if (!func->IsOOPJIT()) // in-proc jit
         {
             IR::Instr *const newInstr = IR::Instr::New(Js::OpCode::PUSH, func);
             newInstr->SetSrc1(IR::AddrOpnd::New(bailOutInfo->bailOutRecord, IR::AddrOpndKindDynamicBailOutRecord, func, true));

+ 17 - 0
lib/Common/Memory/PageAllocator.cpp

@@ -176,6 +176,14 @@ PageSegmentBase<T>::PageSegmentBase(PageAllocatorBase<T> * allocator, bool exter
     }
 }
 
+template<typename T>
+PageSegmentBase<T>::PageSegmentBase(PageAllocatorBase<T> * allocator, void* address, uint pageCount, uint committedCount) :
+    SegmentBase(allocator, allocator->maxAllocPageCount), decommitPageCount(0), freePageCount(0)
+{
+    this->address = (char*)address;
+    this->segmentPageCount = pageCount;
+}
+
 #ifdef PAGEALLOCATOR_PROTECT_FREEPAGE
 template<typename T>
 bool
@@ -717,6 +725,15 @@ PageAllocatorBase<T>::AllocPageSegment(DListBase<PageSegmentBase<T>>& segmentLis
     return segment;
 }
 
+template<typename T>
+PageSegmentBase<T> *
+PageAllocatorBase<T>::AllocPageSegment(DListBase<PageSegmentBase<T>>& segmentList, PageAllocatorBase<T> * pageAllocator, void* address, uint pageCount, uint committedCount)
+{
+    PageSegmentBase<T> * segment = segmentList.PrependNode(&NoThrowNoMemProtectHeapAllocator::Instance, pageAllocator, address, pageCount, committedCount);
+
+    return segment;
+}
+
 template<typename T>
 PageSegmentBase<T> *
 PageAllocatorBase<T>::AddPageSegment(DListBase<PageSegmentBase<T>>& segmentList)

+ 6 - 0
lib/Common/Memory/PageAllocator.h

@@ -10,6 +10,7 @@ struct PageMemoryData;
 #endif
 
 class CodeGenNumberThreadAllocator;
+struct XProcNumberPageSegmentManager;
 
 namespace Memory
 {
@@ -196,6 +197,7 @@ class PageSegmentBase : public SegmentBase<TVirtualAlloc>
 {
 public:
     PageSegmentBase(PageAllocatorBase<TVirtualAlloc> * allocator, bool external);
+    PageSegmentBase(PageAllocatorBase<TVirtualAlloc> * allocator, void* address, uint pageCount, uint committedCount);
     // Maximum possible size of a PageSegment; may be smaller.
     static const uint MaxDataPageCount = 256;     // 1 MB
     static const uint MaxGuardPageCount = 16;
@@ -360,6 +362,7 @@ template<typename TVirtualAlloc>
 class PageAllocatorBase
 {
     friend class CodeGenNumberThreadAllocator;
+    friend struct XProcNumberPageSegmentManager;
     // Allowing recycler to report external memory allocation.
     friend class Recycler;
 public:
@@ -557,6 +560,7 @@ protected:
 #endif
     virtual PageSegmentBase<TVirtualAlloc> * AddPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList);
     static PageSegmentBase<TVirtualAlloc> * AllocPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList, PageAllocatorBase<TVirtualAlloc> * pageAllocator, bool external);
+    static PageSegmentBase<TVirtualAlloc> * AllocPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList, PageAllocatorBase<TVirtualAlloc> * pageAllocator, void* address, uint pageCount, uint committedCount);
 
     // Zero Pages
     void AddPageToZeroQueue(__in void * address, uint pageCount, __in PageSegmentBase<TVirtualAlloc> * pageSegment);
@@ -632,6 +636,8 @@ protected:
     friend class PageSegmentBase<TVirtualAlloc>;
     friend class IdleDecommit;
 
+    void SetProcessHandle(HANDLE hProcess) { processHandle = hProcess; }
+
 protected:
     virtual bool CreateSecondaryAllocator(SegmentBase<TVirtualAlloc>* segment, SecondaryAllocator** allocator)
     {

+ 1 - 0
lib/Common/Memory/Recycler.h

@@ -623,6 +623,7 @@ class Recycler
 #endif
     friend class ScriptEngineBase;  // This is for disabling GC for certain Host operations.
     friend class CodeGenNumberThreadAllocator;
+    friend struct XProcNumberPageSegmentManager;
 public:
     static const uint ConcurrentThreadStackSize = 300000;
     static const bool FakeZeroLengthArray = true;

+ 0 - 1
lib/Common/Memory/Recycler.inl

@@ -25,7 +25,6 @@ Recycler::IntegrateBlock(char * blockAddress, PageSegment * segment, size_t allo
     {
         TrackAllocData trackAllocData;
         ClearTrackAllocInfo(&trackAllocData);
-
         TrackIntegrate(blockAddress, SmallAllocationBlockAttributes::PageCount * AutoSystemInfo::PageSize, allocSize, objectSize, trackAllocData);
     }
 #endif

+ 18 - 0
lib/JITIDL/ChakraJIT.idl

@@ -354,6 +354,21 @@ typedef struct FunctionJITTimeData
     struct FunctionJITTimeData * next;
 } FunctionJITTimeData;
 
+typedef struct XProcNumberPageSegment
+{
+    __int3264 pageAddress;
+    __int3264 allocStartAddress;
+    __int3264 allocEndAddress;
+    __int3264 pageSegment;
+    __int3264 chunkAllocator;
+    struct XProcNumberPageSegment* nextSegment;
+    unsigned int blockSize; // 2 pages
+    unsigned int committedEnd;
+    unsigned int pageCount; // REVIEW: don't actually need these two fields, they are constant
+    unsigned int sizeCat;
+    unsigned int blockIntegratedSize;
+} XProcNumberPageSegment;
+
 // CodeGenWorkItem fields, read only in JIT
 typedef struct CodeGenWorkItemJITData
 {
@@ -362,6 +377,7 @@ typedef struct CodeGenWorkItemJITData
     char jitMode;
 
     unsigned int loopNumber;
+    XProcNumberPageSegment xProcNumberPageSegment;
 
     FunctionJITTimeData * jitData;
     __int3264 nativeDataAddr;
@@ -414,6 +430,8 @@ typedef struct JITOutputData
 
     __int64 codeAddress;
     __int64 xdataAddr;
+
+    XProcNumberPageSegment* numberPageSegments;
     
     unsigned int inlineeFrameOffsetArrayOffset;
     unsigned int inlineeFrameOffsetArrayCount;

+ 3 - 0
lib/JITServer/JITServer.cpp

@@ -175,6 +175,9 @@ ServerRemoteCodeGen(
 
     JITTimeWorkItem * jitWorkItem = Anew(&jitArena, JITTimeWorkItem, workItemData);
 
+    jitData->numberPageSegments = (XProcNumberPageSegment*)midl_user_allocate(sizeof(XProcNumberPageSegment));
+    memcpy_s(jitData->numberPageSegments, sizeof(XProcNumberPageSegment), &jitWorkItem->GetWorkItemData()->xProcNumberPageSegment, sizeof(XProcNumberPageSegment));
+
     Func func(&jitArena, jitWorkItem, threadContextInfo, scriptContextInfo, jitData, nullptr, nullptr, threadContextInfo->GetCodeGenAllocators(), nullptr, nullptr, true);
     func.m_symTable->SetStartingID(static_cast<SymID>(jitWorkItem->GetJITFunctionBody()->GetLocalsCount() + 1));
     func.Codegen();

+ 2 - 2
lib/Runtime/Base/FunctionBody.cpp

@@ -8364,8 +8364,8 @@ namespace Js
 
     InlineeFrameRecord* EntryPointInfo::FindInlineeFrame(void* returnAddress)
     {
-        if (false) // in-proc JIT
-        { 
+        if (this->nativeDataBuffer == nullptr) // in-proc JIT
+        {
             if (this->inlineeFrameMap == nullptr)
             {
                 return nullptr;

+ 2 - 0
lib/Runtime/Base/FunctionBody.h

@@ -529,6 +529,8 @@ namespace Js
 
         char** GetNativeDataBufferRef() { return &nativeDataBuffer; }
 
+        void SetNumberChunks(CodeGenNumberChunk * chunks) { numberChunks = chunks; }
+
     private:
 #if ENABLE_NATIVE_CODEGEN
         typedef SListCounted<ConstructorCache*, Recycler> ConstructorCacheList;

+ 11 - 0
lib/Runtime/Base/ThreadContext.cpp

@@ -164,6 +164,7 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager,
     entryPointToBuiltInOperationIdCache(&threadAlloc, 0),
 #if ENABLE_NATIVE_CODEGEN
     codeGenNumberThreadAllocator(nullptr),
+    xProcNumberPageSegmentManager(nullptr),
 #endif
     dynamicObjectEnumeratorCacheMap(&HeapAllocator::Instance, 16),
     //threadContextFlags(ThreadContextFlagNoFlag),
@@ -432,6 +433,8 @@ ThreadContext::~ThreadContext()
 #if ENABLE_NATIVE_CODEGEN
         HeapDelete(this->codeGenNumberThreadAllocator);
         this->codeGenNumberThreadAllocator = nullptr;
+        HeapDelete(this->xProcNumberPageSegmentManager);
+        this->xProcNumberPageSegmentManager = nullptr;
 #endif
 
         if (this->debugManager != nullptr)
@@ -680,6 +683,9 @@ Recycler* ThreadContext::EnsureRecycler()
         // otherwise, the recycler dtor may encounter problems
         AutoPtr<CodeGenNumberThreadAllocator> localCodeGenNumberThreadAllocator(
             HeapNew(CodeGenNumberThreadAllocator, newRecycler));
+        AutoPtr<XProcNumberPageSegmentManager> localXProcNumberPageSegmentManager(
+            HeapNew(XProcNumberPageSegmentManager, newRecycler));
+        
 #endif
 
         this->recyclableData.Root(RecyclerNewZ(newRecycler, RecyclableData, newRecycler), newRecycler);
@@ -711,6 +717,7 @@ Recycler* ThreadContext::EnsureRecycler()
             InitializePropertyMaps(); // has many dependencies on the recycler and other members of the thread context
 #if ENABLE_NATIVE_CODEGEN
             this->codeGenNumberThreadAllocator = localCodeGenNumberThreadAllocator.Detach();
+            this->xProcNumberPageSegmentManager = localXProcNumberPageSegmentManager.Detach();
 #endif
         }
         catch(...)
@@ -2295,6 +2302,10 @@ ThreadContext::PreCollectionCallBack(CollectionFlags flags)
         {
             codeGenNumberThreadAllocator->Integrate();
         }
+        if (this->xProcNumberPageSegmentManager)
+        {
+            this->xProcNumberPageSegmentManager->Integrate();
+        }
 #endif
     }
 

+ 5 - 0
lib/Runtime/Base/ThreadContext.h

@@ -655,6 +655,7 @@ private:
     JsUtil::JobProcessor *jobProcessor;
     Js::Var * bailOutRegisterSaveSpace;
     CodeGenNumberThreadAllocator * codeGenNumberThreadAllocator;
+    XProcNumberPageSegmentManager * xProcNumberPageSegmentManager;
 #endif
 
     RecyclerRootPtr<RecyclableData> recyclableData;
@@ -1125,6 +1126,10 @@ public:
     {
         return codeGenNumberThreadAllocator;
     }
+    XProcNumberPageSegmentManager * GetXProcNumberPageSegmentManager() const
+    {
+        return this->xProcNumberPageSegmentManager;
+    }
 #endif
     void ResetFunctionCount() { Assert(this->GetScriptSiteHolderCount() == 0); this->functionCount = 0; }
     void PushEntryExitRecord(Js::ScriptEntryExitRecord *);

+ 1 - 1
lib/Runtime/Library/JavascriptNumber.h

@@ -19,7 +19,7 @@ namespace Js
 #endif
     public:
         JavascriptNumber(double value, StaticType*);
-
+        JavascriptNumber(double value, StaticType*, bool oopJIT);
         static uint32 GetValueOffset()
         {
             return offsetof(JavascriptNumber, m_value);

+ 4 - 0
lib/Runtime/Library/JavascriptNumber.inl

@@ -18,6 +18,10 @@ namespace Js
     {
         Assert(type->GetTypeId() == TypeIds_Number);
     }
+
+    __inline JavascriptNumber::JavascriptNumber(double value, StaticType * type, bool oopJIT) : RecyclableObject(type), m_value(value)
+    {
+    }
 #endif
 
     __forceinline Var JavascriptNumber::ToVar(int32 nValue, ScriptContext* scriptContext)

+ 4 - 1
lib/Runtime/Types/RecyclableObject.cpp

@@ -108,7 +108,10 @@ namespace Js
 #endif
 #endif
 #if DBG || defined(PROFILE_TYPES)
-        RecordAllocation(type->GetScriptContext());
+        if (false) // In-proc JIT
+        {
+            RecordAllocation(type->GetScriptContext());
+        }
 #endif
     }