Pārlūkot izejas kodu

Refactor field related to JIT'ed code in EntryPointInfo into a separate structure

Reduced FunctionEntryPointInfo from 336 bytes to 96 bytes in 64 bits
Also fix an issue that JitTransferData wasn't deleted when SimpleJit work completes.

Reduce memory usage of MS Teams page load by 6MB
Curtis Man 7 gadi atpakaļ
vecāks
revīzija
3741b1a94a

+ 1 - 1
lib/Backend/BailOut.cpp

@@ -1130,7 +1130,7 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail
             // While bailing out, RestoreFrames should box all Vars on the stack. If there are multiple Vars pointing to the same
             // object, the cached version (that was previously boxed) will be reused to maintain pointer identity and correctness
             // after the transition to the interpreter.
-            InlinedFrameLayout* outerMostFrame = (InlinedFrameLayout *)(((uint8 *)Js::JavascriptCallStackLayout::ToFramePointer(layout)) - entryPointInfo->frameHeight);
+            InlinedFrameLayout* outerMostFrame = (InlinedFrameLayout *)(((uint8 *)Js::JavascriptCallStackLayout::ToFramePointer(layout)) - entryPointInfo->GetFrameHeight());
             inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, true /* boxArgs */);
         }
     }

+ 2 - 0
lib/Backend/CMakeLists.txt

@@ -51,6 +51,7 @@ add_library (Chakra.Backend OBJECT
     JITTimePolymorphicInlineCacheInfo.cpp
     JITTimeProfileInfo.cpp
     JITTimeWorkItem.cpp
+    JitTransferData.cpp
     JITType.cpp
     JITTypeHandler.cpp
     JnHelperMethod.cpp
@@ -60,6 +61,7 @@ add_library (Chakra.Backend OBJECT
     LowerMDSharedSimd128.cpp
     NativeCodeData.cpp
     NativeCodeGenerator.cpp
+    NativeEntryPointData.cpp
     ObjTypeSpecFldInfo.cpp
     Opnd.cpp
     PDataManager.cpp

+ 4 - 0
lib/Backend/Chakra.Backend.vcxproj

@@ -253,8 +253,12 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)ValueInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITThunkEmitter.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)IntConstMath.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)NativeEntryPointData.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)JitTransferData.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="JitTransferData.h" />
+    <ClInclude Include="NativeEntryPointData.h" />
     <ClInclude Include="AgenPeeps.h" />
     <ClInclude Include="arm64\ARM64Encoder.h">
       <ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>

+ 12 - 7
lib/Backend/CodeGenWorkItem.cpp

@@ -4,6 +4,7 @@
 //-------------------------------------------------------------------------------------------------------
 #include "Backend.h"
 #include "Language/SourceDynamicProfileManager.h"
+#include "NativeEntryPointData.h"
 
 CodeGenWorkItem::CodeGenWorkItem(
     JsUtil::JobManager *const manager,
@@ -184,7 +185,7 @@ void CodeGenWorkItem::OnRemoveFromJitQueue(NativeCodeGenerator* generator)
         // Go ahead and delete it and let it re-queue if more interpreting of the loop happens
         auto loopBodyWorkItem = static_cast<JsLoopBodyCodeGen*>(this);
         loopBodyWorkItem->loopHeader->ResetInterpreterCount();
-        loopBodyWorkItem->GetEntryPoint()->Reset();
+        loopBodyWorkItem->GetEntryPoint()->Reset(true);
         HeapDelete(loopBodyWorkItem);
     }
     else
@@ -207,15 +208,19 @@ void CodeGenWorkItem::OnWorkItemProcessFail(NativeCodeGenerator* codeGen)
 #endif
 
 #if PDATA_ENABLED & defined(_WIN32)
-        if (this->entryPointInfo && this->entryPointInfo->GetXDataInfo()) 
+        if (this->entryPointInfo)
         {
-            void* functionTable = this->entryPointInfo->GetXDataInfo()->functionTable;
-            if (functionTable)
+            XDataAllocation * xdataAllocation = this->entryPointInfo->GetNativeEntryPointData()->GetXDataInfo();
+            if (xdataAllocation)
             {
-                if (!DelayDeletingFunctionTable::AddEntry(functionTable))
+                void* functionTable = xdataAllocation->functionTable;
+                if (functionTable)
                 {
-                    PHASE_PRINT_TESTTRACE1(Js::XDataPhase, _u("OnWorkItemProcessFail: Failed to add to slist, table: %llx\n"), functionTable);
-                    DelayDeletingFunctionTable::DeleteFunctionTable(functionTable);
+                    if (!DelayDeletingFunctionTable::AddEntry(functionTable))
+                    {
+                        PHASE_PRINT_TESTTRACE1(Js::XDataPhase, _u("OnWorkItemProcessFail: Failed to add to slist, table: %llx\n"), functionTable);
+                        DelayDeletingFunctionTable::DeleteFunctionTable(functionTable);
+                    }
                 }
             }
         }

+ 12 - 14
lib/Backend/Encoder.cpp

@@ -4,6 +4,8 @@
 //-------------------------------------------------------------------------------------------------------
 #include "Backend.h"
 #include "Core/CRC.h"
+#include "NativeEntryPointData.h"
+#include "JitTransferData.h"
 
 ///----------------------------------------------------------------------------
 ///
@@ -74,8 +76,8 @@ Encoder::Encode()
 #endif
 
     m_pc = m_encodeBuffer;
-    m_inlineeFrameMap = Anew(m_tempAlloc, InlineeFrameMap, m_tempAlloc);
-    m_bailoutRecordMap = Anew(m_tempAlloc, BailoutRecordMap, m_tempAlloc);
+    m_inlineeFrameMap = Anew(m_tempAlloc, ArenaInlineeFrameMap, m_tempAlloc);
+    m_bailoutRecordMap = Anew(m_tempAlloc, ArenaBailoutRecordMap, m_tempAlloc);
 
     IR::PragmaInstr* pragmaInstr = nullptr;
     uint32 pragmaOffsetInBuffer = 0;
@@ -435,7 +437,7 @@ Encoder::Encode()
     else
     {
         XDataAllocator::Register(&allocation->xdata, m_func->GetJITOutput()->GetCodeAddress(), (DWORD)m_func->GetJITOutput()->GetCodeSize());
-        m_func->GetInProcJITEntryPointInfo()->SetXDataInfo(&allocation->xdata);
+        m_func->GetInProcJITEntryPointInfo()->GetNativeEntryPointData()->SetXDataInfo(&allocation->xdata);
     }
     m_func->GetJITOutput()->SetCodeAddress(m_func->GetJITOutput()->GetCodeAddress() | 0x1); // Set thumb mode
 #endif
@@ -447,7 +449,7 @@ Encoder::Encode()
     {
         if (!m_func->IsOOPJIT()) // in-proc JIT
         {
-            m_func->GetInProcJITEntryPointInfo()->RecordInlineeFrameMap(m_inlineeFrameMap);
+            m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->RecordInlineeFrameMap(m_inlineeFrameMap);
         }
         else // OOP JIT
         {
@@ -472,7 +474,7 @@ Encoder::Encode()
 
     if (this->m_bailoutRecordMap->Count() > 0)
     {
-        m_func->GetInProcJITEntryPointInfo()->RecordBailOutMap(m_bailoutRecordMap);
+        m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->RecordBailOutMap(m_bailoutRecordMap);
     }
 
     if (this->m_func->pinnedTypeRefs != nullptr)
@@ -492,7 +494,6 @@ Encoder::Encode()
 
             pinnedTypeRefs->count = pinnedTypeRefCount;
             pinnedTypeRefs->isOOPJIT = true;
-            this->m_func->GetJITOutput()->GetOutputData()->pinnedTypeRefs = pinnedTypeRefs;
         }
         else
         {
@@ -515,10 +516,7 @@ Encoder::Encode()
             Output::Flush();
         }
 
-        if (!this->m_func->IsOOPJIT())
-        {
-            m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetRuntimeTypeRefs(pinnedTypeRefs);
-        }
+        this->m_func->GetJITOutput()->GetOutputData()->pinnedTypeRefs = pinnedTypeRefs;
     }
 
     // Save all equivalent type guards in a fixed size array on the JIT transfer data
@@ -642,7 +640,7 @@ Encoder::Encode()
 
             Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(typeGuardTransferRecord) + typeGuardTransferSize + sizeof(Js::TypeGuardTransferEntry));
 
-            m_func->GetInProcJITEntryPointInfo()->RecordTypeGuards(this->m_func->indexedPropertyGuardCount, typeGuardTransferRecord, typeGuardTransferSize);
+            m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->RecordTypeGuards(this->m_func->indexedPropertyGuardCount, typeGuardTransferRecord, typeGuardTransferSize);
         }
         else
         {
@@ -730,7 +728,7 @@ Encoder::Encode()
         }
         else
         {
-            Assert(m_func->GetInProcJITEntryPointInfo()->GetConstructorCacheCount() > 0);
+            Assert(m_func->GetInProcJITEntryPointInfo()->GetNativeEntryPointData()->GetConstructorCacheCount() > 0);
 
             size_t ctorCachesTransferSize =                                // Reserve enough room for:
                 propertyCount * sizeof(Js::CtorCacheGuardTransferEntry) +  //   each propertyId,
@@ -763,7 +761,7 @@ Encoder::Encode()
 
             Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(ctorCachesTransferRecord) + ctorCachesTransferSize + sizeof(Js::CtorCacheGuardTransferEntry));
 
-            m_func->GetInProcJITEntryPointInfo()->RecordCtorCacheGuards(ctorCachesTransferRecord, ctorCachesTransferSize);
+            m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->RecordCtorCacheGuards(ctorCachesTransferRecord, ctorCachesTransferSize);
         }
     }
     m_func->GetJITOutput()->FinalizeNativeCode();
@@ -1413,7 +1411,7 @@ void Encoder::CopyMaps(OffsetList **m_origInlineeFrameRecords
     )
 {
     InlineeFrameRecords *recList = m_inlineeFrameRecords;
-    InlineeFrameMap *mapList = m_inlineeFrameMap;
+    ArenaInlineeFrameMap *mapList = m_inlineeFrameMap;
     PragmaInstrList *pInstrList = m_pragmaInstrToRecordOffset;
 
     OffsetList *origRecList, *origMapList, *origPInstrList;

+ 4 - 4
lib/Backend/Encoder.h

@@ -11,7 +11,7 @@
 ///
 ///---------------------------------------------------------------------------
 
-typedef JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator> InlineeFrameMap;
+typedef JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator> ArenaInlineeFrameMap;
 typedef JsUtil::List<IR::PragmaInstr*, ArenaAllocator> PragmaInstrList;
 typedef JsUtil::List<uint32, ArenaAllocator> OffsetList;
 typedef JsUtil::List<BranchJumpTableWrapper*, ArenaAllocator> JmpTableList;
@@ -35,11 +35,11 @@ private:
     uint32          m_encodeBufferSize;
     ArenaAllocator *m_tempAlloc;
 
-    InlineeFrameMap* m_inlineeFrameMap;
+    ArenaInlineeFrameMap* m_inlineeFrameMap;
     uint32 m_inlineeFrameMapDataOffset;
     uint32 m_inlineeFrameMapRecordCount;
-    typedef JsUtil::List<LazyBailOutRecord, ArenaAllocator> BailoutRecordMap;
-    BailoutRecordMap* m_bailoutRecordMap;
+    typedef JsUtil::List<LazyBailOutRecord, ArenaAllocator> ArenaBailoutRecordMap;
+    ArenaBailoutRecordMap* m_bailoutRecordMap;
 #if DBG_DUMP
     void DumpInlineeFrameMap(size_t baseAddress);
     uint32 *        m_offsetBuffer;

+ 4 - 2
lib/Backend/JITOutput.cpp

@@ -4,6 +4,8 @@
 //-------------------------------------------------------------------------------------------------------
 
 #include "Backend.h"
+#include "NativeEntryPointData.h"
+#include "JitTransferData.h"
 
 JITOutput::JITOutput(JITOutputIDL * outputData) :
     m_outputData(outputData),
@@ -267,11 +269,11 @@ JITOutput::FinalizeNativeCode()
 #endif
     {
         m_func->GetInProcCodeGenAllocators()->emitBufferManager.CompletePreviousAllocation(m_inProcAlloc);
-        m_func->GetInProcJITEntryPointInfo()->SetInProcJITNativeCodeData(m_func->GetNativeCodeDataAllocator()->Finalize());
+        m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->SetNativeCodeData(m_func->GetNativeCodeDataAllocator()->Finalize());
         m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetRawData(m_func->GetTransferDataAllocator()->Finalize());
 #if !FLOATVAR
         CodeGenNumberChunk * numberChunks = m_func->GetNumberAllocator()->Finalize();
-        m_func->GetInProcJITEntryPointInfo()->SetNumberChunks(numberChunks);
+        m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->SetNumberChunks(numberChunks);
 #endif
 
 #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)

+ 118 - 0
lib/Backend/JitTransferData.cpp

@@ -0,0 +1,118 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+#include "Backend.h"
+#include "JitTransferData.h"
+
+using namespace Js;
+
+void JitTransferData::AddJitTimeTypeRef(void* typeRef, Recycler* recycler)
+{
+    Assert(typeRef != nullptr);
+    EnsureJitTimeTypeRefs(recycler);
+    this->jitTimeTypeRefs->AddNew(typeRef);
+}
+
+void JitTransferData::EnsureJitTimeTypeRefs(Recycler* recycler)
+{
+    if (this->jitTimeTypeRefs == nullptr)
+    {
+        this->jitTimeTypeRefs = RecyclerNew(recycler, TypeRefSet, recycler);
+    }
+}
+
+void JitTransferData::RecordTypeGuards(int typeGuardCount, TypeGuardTransferEntry* typeGuardTransferRecord, size_t typeGuardTransferPlusSize)
+{
+    this->propertyGuardCount = typeGuardCount;
+    this->propertyGuardsByPropertyId = typeGuardTransferRecord;
+    this->propertyGuardsByPropertyIdPlusSize = typeGuardTransferPlusSize;
+}
+
+void JitTransferData::RecordCtorCacheGuards(CtorCacheGuardTransferEntry* ctorCacheTransferRecord, size_t ctorCacheTransferPlusSize)
+{
+    this->ctorCacheGuardsByPropertyId = ctorCacheTransferRecord;
+    this->ctorCacheGuardsByPropertyIdPlusSize = ctorCacheTransferPlusSize;
+}
+
+
+void JitTransferData::Cleanup()
+{
+    // This dictionary is recycler allocated so it doesn't need to be explicitly freed.
+    this->jitTimeTypeRefs = nullptr;
+
+    if (this->lazyBailoutProperties != nullptr)
+    {
+        HeapDeleteArray(this->lazyBailoutPropertyCount, this->lazyBailoutProperties);
+        this->lazyBailoutProperties = nullptr;
+    }
+
+    // All structures below are heap allocated and need to be freed explicitly.
+    if (this->runtimeTypeRefs != nullptr)
+    {
+        if (this->runtimeTypeRefs->isOOPJIT)
+        {
+            midl_user_free(this->runtimeTypeRefs);
+        }
+        else
+        {
+            HeapDeletePlus(offsetof(PinnedTypeRefsIDL, typeRefs) + sizeof(void*)*this->runtimeTypeRefs->count - sizeof(PinnedTypeRefsIDL),
+                PointerValue(this->runtimeTypeRefs));
+        }
+        this->runtimeTypeRefs = nullptr;
+    }
+
+    if (this->propertyGuardsByPropertyId != nullptr)
+    {
+        HeapDeletePlus(this->propertyGuardsByPropertyIdPlusSize, this->propertyGuardsByPropertyId);
+        this->propertyGuardsByPropertyId = nullptr;
+    }
+    this->propertyGuardCount = 0;
+    this->propertyGuardsByPropertyIdPlusSize = 0;
+
+    if (this->ctorCacheGuardsByPropertyId != nullptr)
+    {
+        HeapDeletePlus(this->ctorCacheGuardsByPropertyIdPlusSize, this->ctorCacheGuardsByPropertyId);
+        this->ctorCacheGuardsByPropertyId = nullptr;
+    }
+    this->ctorCacheGuardsByPropertyIdPlusSize = 0;
+
+    if (this->equivalentTypeGuards != nullptr)
+    {
+        HeapDeleteArray(this->equivalentTypeGuardCount, this->equivalentTypeGuards);
+        this->equivalentTypeGuards = nullptr;
+    }
+    this->equivalentTypeGuardCount = 0;
+
+    if (this->jitTransferRawData != nullptr)
+    {
+        HeapDelete(this->jitTransferRawData);
+        this->jitTransferRawData = nullptr;
+    }
+
+    if (this->equivalentTypeGuardOffsets)
+    {
+        midl_user_free(this->equivalentTypeGuardOffsets);
+    }
+
+    if (this->typeGuardTransferData.entries != nullptr)
+    {
+        auto next = &this->typeGuardTransferData.entries;
+        while (*next)
+        {
+            auto current = (*next);
+            *next = (*next)->next;
+            midl_user_free(current);
+        }
+    }
+
+    if (this->ctorCacheTransferData.entries != nullptr)
+    {
+        CtorCacheTransferEntryIDL ** entries = this->ctorCacheTransferData.entries;
+        for (uint i = 0; i < this->ctorCacheTransferData.ctorCachesCount; ++i)
+        {
+            midl_user_free(entries[i]);
+        }
+        midl_user_free(entries);
+    }
+}

+ 114 - 0
lib/Backend/JitTransferData.h

@@ -0,0 +1,114 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+#pragma once
+
+namespace Js
+{
+    class EntryPointInfo;
+    class JitEquivalentTypeGuard;
+    struct CtorCacheGuardTransferEntry;
+    struct TypeGuardTransferEntry;
+};
+
+struct TypeGuardTransferData
+{
+    Field(unsigned int) propertyGuardCount;
+    FieldNoBarrier(TypeGuardTransferEntryIDL*) entries;
+};
+
+struct CtorCacheTransferData
+{
+    Field(unsigned int) ctorCachesCount;
+    FieldNoBarrier(CtorCacheTransferEntryIDL **) entries;
+};
+
+class JitTransferData
+{
+    friend Js::EntryPointInfo;
+
+private:
+    typedef JsUtil::BaseHashSet<void*, Recycler, PowerOf2SizePolicy> TypeRefSet;
+    Field(TypeRefSet*) jitTimeTypeRefs;
+
+    Field(PinnedTypeRefsIDL*) runtimeTypeRefs;
+
+    Field(int) propertyGuardCount;
+    // This is a dynamically sized array of dynamically sized TypeGuardTransferEntries.  It's heap allocated by the JIT
+    // thread and lives until entry point is installed, at which point it is explicitly freed.
+    FieldNoBarrier(Js::TypeGuardTransferEntry*) propertyGuardsByPropertyId;
+    Field(size_t) propertyGuardsByPropertyIdPlusSize;
+
+    // This is a dynamically sized array of dynamically sized CtorCacheGuardTransferEntry.  It's heap allocated by the JIT
+    // thread and lives until entry point is installed, at which point it is explicitly freed.
+    FieldNoBarrier(Js::CtorCacheGuardTransferEntry*) ctorCacheGuardsByPropertyId;
+    Field(size_t) ctorCacheGuardsByPropertyIdPlusSize;
+
+    Field(int) equivalentTypeGuardCount;
+    Field(int) lazyBailoutPropertyCount;
+    // This is a dynamically sized array of JitEquivalentTypeGuards. It's heap allocated by the JIT thread and lives
+    // until entry point is installed, at which point it is explicitly freed. We need it during installation so as to
+    // swap the cache associated with each guard from the heap to the recycler (so the types in the cache are kept alive).
+    FieldNoBarrier(Js::JitEquivalentTypeGuard**) equivalentTypeGuards;
+    FieldNoBarrier(Js::PropertyId*) lazyBailoutProperties;
+    FieldNoBarrier(NativeCodeData*) jitTransferRawData;
+    FieldNoBarrier(EquivalentTypeGuardOffsets*) equivalentTypeGuardOffsets;
+    Field(TypeGuardTransferData) typeGuardTransferData;
+    Field(CtorCacheTransferData) ctorCacheTransferData;
+
+    Field(bool) falseReferencePreventionBit;
+    Field(bool) isReady;
+
+public:
+    JitTransferData() :
+        jitTimeTypeRefs(nullptr), runtimeTypeRefs(nullptr),
+        propertyGuardCount(0), propertyGuardsByPropertyId(nullptr), propertyGuardsByPropertyIdPlusSize(0),
+        ctorCacheGuardsByPropertyId(nullptr), ctorCacheGuardsByPropertyIdPlusSize(0),
+        equivalentTypeGuardCount(0), equivalentTypeGuards(nullptr), jitTransferRawData(nullptr),
+        falseReferencePreventionBit(true), isReady(false), lazyBailoutProperties(nullptr), lazyBailoutPropertyCount(0) {}
+
+    void SetRawData(NativeCodeData* rawData) { jitTransferRawData = rawData; }
+
+    void AddJitTimeTypeRef(void* typeRef, Recycler* recycler);
+
+    int GetRuntimeTypeRefCount() { return this->runtimeTypeRefs ? this->runtimeTypeRefs->count : 0; }
+    void** GetRuntimeTypeRefs() { return this->runtimeTypeRefs ? (void**)this->runtimeTypeRefs->typeRefs : nullptr; }
+    void SetRuntimeTypeRefs(PinnedTypeRefsIDL* pinnedTypeRefs) { this->runtimeTypeRefs = pinnedTypeRefs; }
+
+    Js::JitEquivalentTypeGuard** GetEquivalentTypeGuards() const { return this->equivalentTypeGuards; }
+    void SetEquivalentTypeGuards(Js::JitEquivalentTypeGuard** guards, int count)
+    {
+        this->equivalentTypeGuardCount = count;
+        this->equivalentTypeGuards = guards;
+    }
+    void SetLazyBailoutProperties(Js::PropertyId* properties, int count)
+    {
+        this->lazyBailoutProperties = properties;
+        this->lazyBailoutPropertyCount = count;
+    }
+    void SetEquivalentTypeGuardOffsets(EquivalentTypeGuardOffsets* offsets)
+    {
+        equivalentTypeGuardOffsets = offsets;
+    }
+    void SetTypeGuardTransferData(JITOutputIDL* data)
+    {
+        typeGuardTransferData.entries = data->typeGuardEntries;
+        typeGuardTransferData.propertyGuardCount = data->propertyGuardCount;
+    }
+    void SetCtorCacheTransferData(JITOutputIDL * data)
+    {
+        ctorCacheTransferData.entries = data->ctorCacheEntries;
+        ctorCacheTransferData.ctorCachesCount = data->ctorCachesCount;
+    }
+
+    bool GetIsReady() { return this->isReady; }
+    void SetIsReady() { this->isReady = true; }
+
+    void RecordTypeGuards(int propertyGuardCount, Js::TypeGuardTransferEntry* typeGuardTransferRecord, size_t typeGuardTransferPlusSize);
+    void RecordCtorCacheGuards(Js::CtorCacheGuardTransferEntry* ctorCacheTransferRecord, size_t ctorCacheTransferPlusSize);
+
+    void Cleanup();
+private:
+    void EnsureJitTimeTypeRefs(Recycler* recycler);
+};

+ 0 - 4
lib/Backend/LowerMDShared.h

@@ -182,14 +182,10 @@ public:
             IR::RegOpnd*    MaterializeConstFromBits(int intConst, IRType type, IR::Instr* instr);
             IR::Opnd*       Subtract2To31(IR::Opnd* src1, IR::Opnd* intMinFP, IRType type, IR::Instr* instr);
             bool            TryGenerateFastMulAdd(IR::Instr * instrAdd, IR::Instr ** pInstrPrev);
-            BVSparse<JitArenaAllocator>* GatherFltTmps();
             void            GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMethod helperMethod);
             void            HelperCallForAsmMathBuiltin(IR::Instr* instr, IR::JnHelperMethod helperMethodFloat, IR::JnHelperMethod helperMethodDouble);
             void            GenerateFastInlineBuiltInMathAbs(IR::Instr* instr);
             void            GenerateFastInlineBuiltInMathPow(IR::Instr* instr);
-            IR::Instr *     CheckIsOpndNegZero(IR::Opnd* opnd, IR::Instr* instr, IR::LabelInstr* isNeg0Label);
-            IR::Instr *     CloneSlowPath(IR::Instr * instrEndFloatRange, IR::Instr * instrInsert);
-            bool            IsCloneDone(IR::Instr * instr, BVSparse<JitArenaAllocator> *bvTmps);
             IR::Instr *     EnsureAdjacentArgs(IR::Instr * instrArg);
             void            SaveDoubleToVar(IR::RegOpnd * dstOpnd, IR::RegOpnd *opndFloat, IR::Instr *instrOrig, IR::Instr *instrInsert, bool isHelper = false);
 #if !FLOATVAR

+ 48 - 24
lib/Backend/NativeCodeGenerator.cpp

@@ -4,6 +4,8 @@
 //-------------------------------------------------------------------------------------------------------
 #include "Backend.h"
 #include "Base/ScriptContextProfiler.h"
+#include "NativeEntryPointData.h"
+#include "JitTransferData.h"
 
 #if DBG
 Js::JavascriptMethod checkCodeGenThunk;
@@ -964,8 +966,13 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
 
         throw Js::OperationAbortedException();
     }
-
-    workItem->GetJITData()->nativeDataAddr = (__int3264)workItem->GetEntryPoint()->GetNativeDataBufferRef();
+    
+#if ENABLE_OOP_NATIVE_CODEGEN
+    if (JITManager::GetJITManager()->IsOOPJITEnabled())
+    {
+        workItem->GetJITData()->nativeDataAddr = (__int3264)workItem->GetEntryPoint()->GetOOPNativeEntryPointData()->GetNativeDataBufferRef();
+    }
+#endif
 
     // TODO: oop jit can we be more efficient here?
     ArenaAllocator alloc(_u("JitData"), pageAllocator, Js::Throw::OutOfMemory);
@@ -1015,7 +1022,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         Output::Flush();
     }
 
-    workItem->GetFunctionBody()->SetFrameHeight(workItem->GetEntryPoint(), jitWriteData.frameHeight);
+    epInfo->GetNativeEntryPointData()->SetFrameHeight(jitWriteData.frameHeight);    
 
     if (workItem->Type() == JsFunctionType)
     {
@@ -1029,6 +1036,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         workItem->GetEntryPoint()->SetHasJittedStackClosure();
     }
 
+#if ENABLE_OOP_NATIVE_CODEGEN
 #if !FLOATVAR
     if (jitWriteData.numberPageSegments)
     {
@@ -1040,11 +1048,13 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         else
         {
             // TODO: when codegen fail, need to return the segment as well
-            epInfo->SetNumberPageSegment(jitWriteData.numberPageSegments);
+            epInfo->GetOOPNativeEntryPointData()->SetNumberPageSegment(jitWriteData.numberPageSegments);
         }
     }
 #endif
+#endif
 
+#if ENABLE_OOP_NATIVE_CODEGEN
     if (JITManager::GetJITManager()->IsOOPJITEnabled())
     {
         if (jitWriteData.nativeDataFixupTable)
@@ -1080,7 +1090,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
             jitWriteData.nativeDataFixupTable = nullptr;
 
             // change the address with the fixup information
-            *epInfo->GetNativeDataBufferRef() = (char*)jitWriteData.buffer->data;
+            epInfo->GetOOPNativeEntryPointData()->SetNativeDataBuffer((char*)jitWriteData.buffer->data);
 
 #if DBG
             if (PHASE_TRACE1(Js::NativeCodeDataPhase))
@@ -1090,8 +1100,6 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
 #endif
         }
 
-        epInfo->GetJitTransferData()->SetRuntimeTypeRefs(jitWriteData.pinnedTypeRefs);
-
         if (jitWriteData.throwMapCount > 0)
         {
             Js::ThrowMapEntry * throwMap = (Js::ThrowMapEntry *)(jitWriteData.buffer->data + jitWriteData.throwMapOffset);
@@ -1101,26 +1109,33 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
                 workItem->RecordNativeThrowMap(iter, throwMap[i].nativeBufferOffset, throwMap[i].statementIndex);
             }
         }
+
+        epInfo->GetOOPNativeEntryPointData()->RecordInlineeFrameOffsetsInfo(jitWriteData.inlineeFrameOffsetArrayOffset, jitWriteData.inlineeFrameOffsetArrayCount);
     }
+#endif
 
     if (workItem->GetJitMode() != ExecutionMode::SimpleJit)
     {
-        epInfo->RecordInlineeFrameOffsetsInfo(jitWriteData.inlineeFrameOffsetArrayOffset, jitWriteData.inlineeFrameOffsetArrayCount);
-
+        epInfo->GetJitTransferData()->SetRuntimeTypeRefs(jitWriteData.pinnedTypeRefs);
         epInfo->GetJitTransferData()->SetEquivalentTypeGuardOffsets(jitWriteData.equivalentTypeGuardOffsets);
         epInfo->GetJitTransferData()->SetTypeGuardTransferData(&jitWriteData);
 
-        Assert(jitWriteData.ctorCacheEntries == nullptr || epInfo->GetConstructorCacheCount() > 0);
+        Assert(jitWriteData.ctorCacheEntries == nullptr || epInfo->GetNativeEntryPointData()->GetConstructorCacheCount() > 0);
         epInfo->GetJitTransferData()->SetCtorCacheTransferData(&jitWriteData);
 
         workItem->GetEntryPoint()->GetJitTransferData()->SetIsReady();
     }
+    else
+    {
+        Assert(jitWriteData.pinnedTypeRefs == nullptr);
+    }
+
 
 #if defined(TARGET_64)
     XDataAllocation * xdataInfo = HeapNewZ(XDataAllocation);
     xdataInfo->address = (byte*)jitWriteData.xdataAddr;
     XDataAllocator::Register(xdataInfo, jitWriteData.codeAddress, jitWriteData.codeSize);
-    epInfo->SetXDataInfo(xdataInfo);
+    epInfo->GetNativeEntryPointData()->SetXDataInfo(xdataInfo);
 #endif
 
 
@@ -1152,7 +1167,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         }
         // unmask thumb mode from code address
         XDataAllocator::Register(xdataInfo, jitWriteData.codeAddress & ~0x1, jitWriteData.codeSize);
-        epInfo->SetXDataInfo(xdataInfo);
+        epInfo->GetNativeEntryPointData()->SetXDataInfo(xdataInfo);
     }
 #endif
 
@@ -1173,7 +1188,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         ((JsLoopBodyCodeGen*)workItem)->SetCodeAddress(jitWriteData.codeAddress);
     }
 
-    workItem->GetEntryPoint()->SetCodeGenRecorded((Js::JavascriptMethod)jitWriteData.thunkAddress, (Js::JavascriptMethod)jitWriteData.codeAddress, jitWriteData.codeSize);
+    workItem->GetEntryPoint()->SetCodeGenRecorded((Js::JavascriptMethod)jitWriteData.thunkAddress, (Js::JavascriptMethod)jitWriteData.codeAddress, jitWriteData.codeSize, (void *)this);
 
     if (jitWriteData.hasBailoutInstr != FALSE)
     {
@@ -2061,6 +2076,7 @@ NativeCodeGenerator::JobProcessed(JsUtil::Job *const job, const bool succeeded)
 
             if (entryPointInfo)
             {
+#if ENABLE_ENTRYPOINT_CLEANUP_TRACE
 #if ENABLE_DEBUG_CONFIG_OPTIONS
                 switch (job->failureReason)
                 {
@@ -2071,6 +2087,7 @@ NativeCodeGenerator::JobProcessed(JsUtil::Job *const job, const bool succeeded)
                 case Job::FailureReason::Unknown: entryPointInfo->SetCleanupReason(Js::EntryPointInfo::CleanupReason::CodeGenFailedUnknown); break;
                 default: Assert(job->failureReason == Job::FailureReason::NotFailed);
                 }
+#endif
 #endif
 
                 entryPointInfo->SetPendingCleanup();
@@ -2268,13 +2285,21 @@ NativeCodeGenerator::GatherCodeGenData(
     }
 #endif
 
+    NativeEntryPointData * nativeEntryPointData;
     if (IsInlinee)
     {
         // This function is recursive
         PROBE_STACK_NO_DISPOSE(scriptContext, Js::Constants::MinStackDefault);
+        nativeEntryPointData = entryPoint->GetNativeEntryPointData();;
     }
     else
     {
+        // TODO: For now, we create the native entry point data and the jit transfer data when we queue up
+        // the entry point for code gen, but not clear/free then then the work item got knocked off the queue
+        // without code gen happening.  
+        nativeEntryPointData = entryPoint->EnsureNativeEntryPointData();
+        nativeEntryPointData->EnsureJitTransferData(recycler);
+
         //TryAggressiveInlining adjusts inlining heuristics and walks the call tree. If it can inlining everything it will set the InliningThreshold to be aggressive.
         if (!inliningDecider.GetIsLoopBody())
         {
@@ -2297,10 +2322,9 @@ NativeCodeGenerator::GatherCodeGenData(
                 inliningDecider.ResetState();
             }
         }
-        entryPoint->EnsurePolymorphicInlineCacheInfo(recycler, functionBody);
+        nativeEntryPointData->EnsurePolymorphicInlineCacheInfo(recycler, functionBody);
     }
 
-    entryPoint->EnsureJitTransferData(recycler);
 #if ENABLE_DEBUG_CONFIG_OPTIONS
     char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
 #endif
@@ -2330,9 +2354,9 @@ NativeCodeGenerator::GatherCodeGenData(
                 _u("Objtypespec (%s): Pending cache state on add %x to JIT queue: %d\n"),
                 functionBody->GetDebugNumberSet(debugStringBuffer), entryPoint, profileData->GetPolymorphicCacheState());
 
-            entryPoint->SetPendingPolymorphicCacheState(profileData->GetPolymorphicCacheState());
-            entryPoint->SetPendingInlinerVersion(profileData->GetInlinerVersion());
-            entryPoint->SetPendingImplicitCallFlags(profileData->GetImplicitCallFlags());
+            nativeEntryPointData->SetPendingPolymorphicCacheState(profileData->GetPolymorphicCacheState());
+            nativeEntryPointData->SetPendingInlinerVersion(profileData->GetInlinerVersion());
+            nativeEntryPointData->SetPendingImplicitCallFlags(profileData->GetImplicitCallFlags());
         }
 
         if (functionBody->GetProfiledArrayCallSiteCount() != 0)
@@ -2342,7 +2366,7 @@ NativeCodeGenerator::GatherCodeGenData(
             {
                 jitTimeData->SetWeakFuncRef(weakFuncRef);
             }
-            entryPoint->AddWeakFuncRef(weakFuncRef, recycler);
+            entryPoint->GetNativeEntryPointData()->AddWeakFuncRef(weakFuncRef, recycler);
         }
 
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
@@ -2650,14 +2674,14 @@ NativeCodeGenerator::GatherCodeGenData(
 #endif
 
                     byte polyCacheUtil = profileData->GetFldInfo(functionBody, i)->polymorphicInlineCacheUtilization;
-                    entryPoint->GetPolymorphicInlineCacheInfo()->SetPolymorphicInlineCache(functionBody, i, polymorphicInlineCache, IsInlinee, polyCacheUtil);
+                    nativeEntryPointData->GetPolymorphicInlineCacheInfo()->SetPolymorphicInlineCache(functionBody, i, polymorphicInlineCache, IsInlinee, polyCacheUtil);
                     if (IsInlinee)
                     {
-                        Assert(entryPoint->GetPolymorphicInlineCacheInfo()->GetInlineeInfo(functionBody)->GetPolymorphicInlineCaches()->GetInlineCache(functionBody, i) == polymorphicInlineCache);
+                        Assert(nativeEntryPointData->GetPolymorphicInlineCacheInfo()->GetInlineeInfo(functionBody)->GetPolymorphicInlineCaches()->GetInlineCache(functionBody, i) == polymorphicInlineCache);
                     }
                     else
                     {
-                        Assert(entryPoint->GetPolymorphicInlineCacheInfo()->GetSelfInfo()->GetPolymorphicInlineCaches()->GetInlineCache(functionBody, i) == polymorphicInlineCache);
+                        Assert(nativeEntryPointData->GetPolymorphicInlineCacheInfo()->GetSelfInfo()->GetPolymorphicInlineCaches()->GetInlineCache(functionBody, i) == polymorphicInlineCache);
                     }
                 }
                 else if(IsInlinee && CONFIG_FLAG(CloneInlinedPolymorphicCaches))
@@ -3095,7 +3119,7 @@ NativeCodeGenerator::GatherCodeGenData(Js::FunctionBody *const topFunctionBody,
 #endif
         GatherCodeGenData<false>(recycler, topFunctionBody, functionBody, entryPoint, inliningDecider, objTypeSpecFldInfoList, jitTimeData, nullptr, function ? Js::JavascriptFunction::FromVar(function) : nullptr, 0);
 
-        jitTimeData->sharedPropertyGuards = entryPoint->GetSharedPropertyGuards(jitTimeData->sharedPropertyGuardCount);
+        jitTimeData->sharedPropertyGuards = entryPoint->GetNativeEntryPointData()->GetSharedPropertyGuards(recycler, jitTimeData->sharedPropertyGuardCount);
 
 #ifdef FIELD_ACCESS_STATS
         Js::FieldAccessStats* fieldAccessStats = entryPoint->EnsureFieldAccessStats(recycler);
@@ -3139,7 +3163,7 @@ NativeCodeGenerator::GatherCodeGenData(Js::FunctionBody *const topFunctionBody,
 
         JITTimePolymorphicInlineCacheInfo::InitializeEntryPointPolymorphicInlineCacheInfo(
             recycler,
-            entryPoint->EnsurePolymorphicInlineCacheInfo(recycler, workItem->GetFunctionBody()),
+            entryPoint->GetNativeEntryPointData()->EnsurePolymorphicInlineCacheInfo(recycler, workItem->GetFunctionBody()),
             jitData);
 
         jitTimeData->SetPolymorphicInlineInfo(jitData->inlineeInfo, jitData->selfInfo, jitData->selfInfo->polymorphicInlineCaches);

+ 569 - 0
lib/Backend/NativeEntryPointData.cpp

@@ -0,0 +1,569 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+#include "Backend.h"
+
+#if ENABLE_NATIVE_CODEGEN
+#include "NativeEntryPointData.h"
+#include "JitTransferData.h"
+
+using namespace Js;
+
+NativeEntryPointData::NativeEntryPointData() :
+    runtimeTypeRefs(nullptr), propertyGuardCount(0), propertyGuardWeakRefs(nullptr), polymorphicInlineCacheInfo(nullptr),
+    equivalentTypeCacheCount(0), equivalentTypeCaches(nullptr), registeredEquivalentTypeCacheRef(nullptr),
+    sharedPropertyGuards(nullptr), constructorCaches(nullptr), weakFuncRefSet(nullptr), jitTransferData(nullptr),
+    nativeThrowSpanSequence(nullptr), codeSize(0), nativeAddress(nullptr), thunkAddress(nullptr), validationCookie(nullptr)
+#if PDATA_ENABLED
+    , xdataInfo(nullptr)
+#endif
+#if DBG_DUMP | defined(VTUNE_PROFILING)
+    , nativeOffsetMaps(&HeapAllocator::Instance)
+#endif
+{
+}
+
+JitTransferData* 
+NativeEntryPointData::EnsureJitTransferData(Recycler* recycler)
+{
+    if (this->jitTransferData == nullptr)
+    {
+        this->jitTransferData = RecyclerNew(recycler, JitTransferData);
+    }
+    return this->jitTransferData;
+}
+
+void
+NativeEntryPointData::FreeJitTransferData()
+{
+    JitTransferData * data = this->jitTransferData;
+    if (data != nullptr)
+    {
+        this->jitTransferData = nullptr;
+        data->Cleanup();
+    }
+}
+
+void
+NativeEntryPointData::RecordNativeCode(Js::JavascriptMethod thunkAddress, Js::JavascriptMethod nativeAddress, ptrdiff_t codeSize, void * validationCookie)
+{
+    Assert(this->thunkAddress == nullptr);
+    Assert(this->nativeAddress == nullptr);
+    Assert(this->codeSize == 0);
+    Assert(this->validationCookie == nullptr);
+
+    this->nativeAddress = nativeAddress;
+    this->thunkAddress = thunkAddress;
+    this->codeSize = codeSize;
+    this->validationCookie = validationCookie;
+}
+
+void
+NativeEntryPointData::FreeNativeCode(ScriptContext * scriptContext, bool isShutdown)
+{
+#if PDATA_ENABLED
+    this->CleanupXDataInfo();
+#endif
+
+    // if scriptContext is shutting down, no need to free that native code
+    if (!isShutdown && this->nativeAddress != nullptr)
+    {
+        // In the debugger case, we might call cleanup after the native code gen that
+        // allocated this entry point has already shutdown. In that case, the validation
+        // check below should fail and we should not try to free this entry point
+        // since it's already been freed
+        Assert(this->validationCookie != nullptr);
+        if (this->validationCookie == scriptContext->GetNativeCodeGenerator())
+        {
+            FreeNativeCodeGenAllocation(scriptContext, this->nativeAddress, this->thunkAddress);
+        }
+    }
+
+#ifdef PERF_COUNTERS
+    PERF_COUNTER_SUB(Code, TotalNativeCodeSize, codeSize);
+    PERF_COUNTER_SUB(Code, FunctionNativeCodeSize,codeSize);
+    PERF_COUNTER_SUB(Code, DynamicNativeCodeSize, codeSize);
+#endif
+
+    this->nativeAddress = nullptr;
+    this->thunkAddress = nullptr;
+    this->codeSize = 0;
+}
+
+void
+NativeEntryPointData::SetTJNativeAddress(Js::JavascriptMethod nativeAddress, void * validationCookie)
+{
+    Assert(this->nativeAddress == nullptr);
+    Assert(this->validationCookie == nullptr);
+    this->nativeAddress = nativeAddress;
+    this->validationCookie = validationCookie;
+}
+
+void 
+NativeEntryPointData::SetTJCodeSize(ptrdiff_t codeSize)
+{
+    Assert(this->codeSize == 0);
+    this->codeSize = codeSize;
+}
+
+void 
+NativeEntryPointData::AddWeakFuncRef(RecyclerWeakReference<FunctionBody> *weakFuncRef, Recycler *recycler)
+{
+    NativeEntryPointData::WeakFuncRefSet * weakFuncRefSet = this->weakFuncRefSet;
+    if (weakFuncRefSet == nullptr)
+    {
+        weakFuncRefSet = RecyclerNew(recycler, WeakFuncRefSet, recycler);
+        this->weakFuncRefSet = weakFuncRefSet;
+    }
+    weakFuncRefSet->AddNew(weakFuncRef);
+}
+
+EntryPointPolymorphicInlineCacheInfo * 
+NativeEntryPointData::EnsurePolymorphicInlineCacheInfo(Recycler * recycler, FunctionBody * functionBody)
+{
+    if (!polymorphicInlineCacheInfo)
+    {
+        polymorphicInlineCacheInfo = RecyclerNew(recycler, EntryPointPolymorphicInlineCacheInfo, functionBody);
+    }
+    return polymorphicInlineCacheInfo;
+}
+
+void 
+NativeEntryPointData::RegisterConstructorCache(Js::ConstructorCache* constructorCache, Recycler* recycler)
+{
+    Assert(constructorCache != nullptr);
+
+    if (!this->constructorCaches)
+    {
+        this->constructorCaches = RecyclerNew(recycler, ConstructorCacheList, recycler);
+    }
+
+    this->constructorCaches->Prepend(constructorCache);
+}
+
+void
+NativeEntryPointData::PinTypeRefs(Recycler * recycler, size_t jitPinnedTypeRefCount, void ** jitPinnedTypeRefs)
+{
+    this->runtimeTypeRefs = RecyclerNewArray(recycler, Field(void*), jitPinnedTypeRefCount + 1);
+    // Can't use memcpy here because we need write barrier triggers.
+    // TODO: optimize this by using Memory::CopyArray instead.
+    for (size_t i = 0; i < jitPinnedTypeRefCount; i++)
+    {
+        this->runtimeTypeRefs[i] = jitPinnedTypeRefs[i];
+    }
+    this->runtimeTypeRefs[jitPinnedTypeRefCount] = nullptr;
+}
+
+PropertyGuard* NativeEntryPointData::RegisterSharedPropertyGuard(Js::PropertyId propertyId, ScriptContext* scriptContext)
+{
+    if (this->sharedPropertyGuards == nullptr)
+    {
+        Recycler* recycler = scriptContext->GetRecycler();
+        this->sharedPropertyGuards = RecyclerNew(recycler, SharedPropertyGuardDictionary, recycler);
+    }
+
+    PropertyGuard* guard = nullptr;
+    if (!this->sharedPropertyGuards->TryGetValue(propertyId, &guard))
+    {
+        ThreadContext* threadContext = scriptContext->GetThreadContext();
+        guard = threadContext->RegisterSharedPropertyGuard(propertyId);
+        this->sharedPropertyGuards->Add(propertyId, guard);
+    }
+    return guard;
+}
+
+Js::PropertyId* NativeEntryPointData::GetSharedPropertyGuards(Recycler * recycler, _Out_ unsigned int& count)
+{
+    Js::PropertyId* sharedPropertyGuards = nullptr;
+    unsigned int guardCount = 0;
+
+    if (this->sharedPropertyGuards != nullptr)
+    {
+        const unsigned int sharedPropertyGuardsCount = (unsigned int)this->sharedPropertyGuards->Count();
+        Js::PropertyId* guards = RecyclerNewArray(recycler, Js::PropertyId, sharedPropertyGuardsCount);
+        auto sharedGuardIter = this->sharedPropertyGuards->GetIterator();
+
+        while (sharedGuardIter.IsValid())
+        {
+            AnalysisAssert(guardCount < sharedPropertyGuardsCount);
+            guards[guardCount] = sharedGuardIter.CurrentKey();
+            sharedGuardIter.MoveNext();
+            ++guardCount;
+        }
+        AnalysisAssert(guardCount == sharedPropertyGuardsCount);
+
+        sharedPropertyGuards = guards;
+    }
+
+    count = guardCount;
+    return sharedPropertyGuards;
+}
+
+bool NativeEntryPointData::TryGetSharedPropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard*& guard)
+{
+    return this->sharedPropertyGuards != nullptr ? this->sharedPropertyGuards->TryGetValue(propertyId, &guard) : false;
+}
+
+EquivalentTypeCache *
+NativeEntryPointData::EnsureEquivalentTypeCache(int guardCount, ScriptContext * scriptContext, EntryPointInfo * entryPointInfo)
+{
+    Assert(this->equivalentTypeCacheCount == 0);
+    Assert(this->equivalentTypeCaches == nullptr);
+
+    // Create an array of equivalent type caches on the entry point info to ensure they are kept
+    // alive for the lifetime of the entry point.
+
+    // No need to zero-initialize, since we will populate all data slots.
+    // We used to let the recycler scan the types in the cache, but we no longer do. See
+    // ThreadContext::ClearEquivalentTypeCaches for an explanation.
+    this->equivalentTypeCaches = RecyclerNewArrayLeafZ(scriptContext->GetRecycler(), EquivalentTypeCache, guardCount);
+    this->equivalentTypeCacheCount = guardCount;
+    this->RegisterEquivalentTypeCaches(scriptContext, entryPointInfo);
+    return this->equivalentTypeCaches;
+}
+
+bool
+NativeEntryPointData::ClearEquivalentTypeCaches(Recycler * recycler)
+{
+    Assert(this->equivalentTypeCaches != nullptr);
+    Assert(this->equivalentTypeCacheCount > 0);
+
+    bool isAnyCacheLive = false;
+    for (EquivalentTypeCache *cache = this->equivalentTypeCaches;
+        cache < this->equivalentTypeCaches + this->equivalentTypeCacheCount;
+        cache++)
+    {
+        bool isCacheLive = cache->ClearUnusedTypes(recycler);
+        if (isCacheLive)
+        {
+            isAnyCacheLive = true;
+        }
+    }
+
+    if (!isAnyCacheLive)
+    {
+        // The caller must take care of unregistering this entry point. We may be in the middle of
+        // walking the list of registered entry points.
+        this->equivalentTypeCaches = nullptr;
+        this->equivalentTypeCacheCount = 0;
+        this->registeredEquivalentTypeCacheRef = nullptr;
+    }
+
+    return isAnyCacheLive;
+}
+
+Field(FakePropertyGuardWeakReference*) *
+NativeEntryPointData::EnsurePropertyGuardWeakRefs(int guardCount, Recycler * recycler)
+{
+    Assert(this->propertyGuardCount == 0);
+    Assert(this->propertyGuardWeakRefs == nullptr);
+    this->propertyGuardWeakRefs = RecyclerNewArrayZ(recycler, Field(FakePropertyGuardWeakReference*), guardCount);
+    this->propertyGuardCount = guardCount;
+
+    return this->propertyGuardWeakRefs;
+}
+void
+NativeEntryPointData::RegisterEquivalentTypeCaches(ScriptContext * scriptContext, EntryPointInfo * entryPointInfo)
+{
+    Assert(this->registeredEquivalentTypeCacheRef == nullptr);
+    this->registeredEquivalentTypeCacheRef = scriptContext->GetThreadContext()->RegisterEquivalentTypeCacheEntryPoint(entryPointInfo);
+}
+
+void
+NativeEntryPointData::UnregisterEquivalentTypeCaches(ScriptContext * scriptContext)
+{
+    EntryPointInfo ** registeredEquivalentTypeCacheRef = this->registeredEquivalentTypeCacheRef;
+
+    if (registeredEquivalentTypeCacheRef != nullptr)
+    {
+        if (scriptContext != nullptr)
+        {
+            scriptContext->GetThreadContext()->UnregisterEquivalentTypeCacheEntryPoint(
+                registeredEquivalentTypeCacheRef);
+        }
+        this->registeredEquivalentTypeCacheRef = nullptr;
+    }
+}
+
+void
+NativeEntryPointData::FreePropertyGuards()
+{
+    // While typePropertyGuardWeakRefs are allocated via NativeCodeData::Allocator and will be automatically freed to the heap,
+    // we must zero out the fake weak references so that property guard invalidation doesn't access freed memory.
+    if (this->propertyGuardWeakRefs != nullptr)
+    {
+        for (int i = 0; i < this->propertyGuardCount; i++)
+        {
+            if (this->propertyGuardWeakRefs[i] != nullptr)
+            {
+                this->propertyGuardWeakRefs[i]->Zero();
+            }
+        }
+        this->propertyGuardCount = 0;
+        this->propertyGuardWeakRefs = nullptr;
+    }
+}
+
+void 
+NativeEntryPointData::ClearTypeRefsAndGuards(ScriptContext * scriptContext)
+{
+    this->runtimeTypeRefs = nullptr;
+    this->FreePropertyGuards();
+    this->equivalentTypeCacheCount = 0;
+    this->equivalentTypeCaches = nullptr;
+    this->UnregisterEquivalentTypeCaches(scriptContext);
+}
+
+#if PDATA_ENABLED
+void
+NativeEntryPointData::CleanupXDataInfo()
+{
+    if (this->xdataInfo != nullptr)
+    {
+#ifdef _WIN32
+        if (this->xdataInfo->functionTable
+            && !DelayDeletingFunctionTable::AddEntry(this->xdataInfo->functionTable))
+        {
+            DelayDeletingFunctionTable::DeleteFunctionTable(this->xdataInfo->functionTable);
+        }
+#endif
+        XDataAllocator::Unregister(this->xdataInfo);
+#if defined(_M_ARM)
+        if (JITManager::GetJITManager()->IsOOPJITEnabled())
+#endif
+        {
+            HeapDelete(this->xdataInfo);
+        }
+        this->xdataInfo = nullptr;
+    }
+}
+#endif //PDATA_ENABLED
+
+void
+NativeEntryPointData::Cleanup(ScriptContext * scriptContext, bool isShutdown, bool reset)
+{    
+    this->FreeJitTransferData();
+    this->FreeNativeCode(scriptContext, isShutdown);
+
+    if (JITManager::GetJITManager()->IsOOPJITEnabled())
+    {
+        ((OOPNativeEntryPointData *)this)->OnCleanup();
+    }
+    else
+    {
+        ((InProcNativeEntryPointData *)this)->OnCleanup();
+    }
+
+    this->ClearTypeRefsAndGuards(scriptContext);
+
+    if (this->sharedPropertyGuards != nullptr)
+    {
+        // Reset can be called on the background thread, don't clear it explicitly
+        if (!reset)
+        {
+            sharedPropertyGuards->Clear();
+        }
+        sharedPropertyGuards = nullptr;
+    }
+
+    if (this->constructorCaches != nullptr)
+    {
+        // Reset can be called on the background thread, don't clear it explicitly
+        if (!reset)
+        {
+            this->constructorCaches->Clear();
+        }
+        this->constructorCaches = nullptr;
+    }
+
+    this->polymorphicInlineCacheInfo = nullptr;
+    this->weakFuncRefSet = nullptr;
+
+    if (this->nativeThrowSpanSequence)
+    {
+        HeapDelete(this->nativeThrowSpanSequence);
+        this->nativeThrowSpanSequence = nullptr;
+    }
+
+#if DBG_DUMP | defined(VTUNE_PROFILING)
+    this->nativeOffsetMaps.Reset();
+#endif
+}
+
+InProcNativeEntryPointData::InProcNativeEntryPointData() :
+    nativeCodeData(nullptr), inlineeFrameMap(nullptr), bailoutRecordMap(nullptr)
+#if !FLOATVAR
+    , numberChunks(nullptr)
+#endif
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+}
+
+void
+InProcNativeEntryPointData::SetNativeCodeData(NativeCodeData * data)
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    Assert(this->nativeCodeData == nullptr);
+    this->nativeCodeData = data;
+}
+
+InlineeFrameMap *
+InProcNativeEntryPointData::GetInlineeFrameMap()
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    return inlineeFrameMap;
+}
+
+void
+InProcNativeEntryPointData::RecordInlineeFrameMap(JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator>* tempInlineeFrameMap)
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    Assert(this->inlineeFrameMap == nullptr);
+    if (tempInlineeFrameMap->Count() > 0)
+    {
+        this->inlineeFrameMap = HeapNew(InlineeFrameMap, &HeapAllocator::Instance);
+        this->inlineeFrameMap->Copy(tempInlineeFrameMap);
+    }
+}
+
+BailOutRecordMap *
+InProcNativeEntryPointData::GetBailOutRecordMap()
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    return this->bailoutRecordMap;
+}
+
+void 
+InProcNativeEntryPointData::RecordBailOutMap(JsUtil::List<LazyBailOutRecord, ArenaAllocator>* bailoutMap)
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    Assert(this->bailoutRecordMap == nullptr);
+    this->bailoutRecordMap = HeapNew(BailOutRecordMap, &HeapAllocator::Instance);
+    this->bailoutRecordMap->Copy(bailoutMap);
+}
+
+void
+InProcNativeEntryPointData::OnCleanup()
+{
+    Assert(!JITManager::GetJITManager()->IsOOPJITEnabled());
+    if (this->nativeCodeData)
+    {
+        DeleteNativeCodeData(this->nativeCodeData);
+        this->nativeCodeData = nullptr;
+    }
+
+    if (this->inlineeFrameMap)
+    {
+        HeapDelete(this->inlineeFrameMap);
+        this->inlineeFrameMap = nullptr;
+    }
+
+    if (this->bailoutRecordMap)
+    {
+        HeapDelete(this->bailoutRecordMap);
+        this->bailoutRecordMap = nullptr;
+    }
+
+#if !FLOATVAR
+    this->numberChunks = nullptr;
+#endif
+}
+
+OOPNativeEntryPointData::OOPNativeEntryPointData() :
+    nativeDataBuffer(nullptr)
+#if !FLOATVAR
+    , numberArray(nullptr), numberPageSegments(nullptr)
+#endif
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+}
+
+char*
+OOPNativeEntryPointData::GetNativeDataBuffer()
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    return nativeDataBuffer;
+}
+
+char**
+OOPNativeEntryPointData::GetNativeDataBufferRef()
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    return &nativeDataBuffer;
+}
+
+void
+OOPNativeEntryPointData::SetNativeDataBuffer(char * buffer)
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    Assert(this->nativeDataBuffer == nullptr);
+    this->nativeDataBuffer = buffer;
+}
+
+uint32
+OOPNativeEntryPointData::GetOffsetOfNativeDataBuffer()
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    return offsetof(OOPNativeEntryPointData, nativeDataBuffer);
+}
+
+uint
+OOPNativeEntryPointData::GetInlineeFrameOffsetArrayOffset() 
+{ 
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    return this->inlineeFrameOffsetArrayOffset; 
+}
+
+uint
+OOPNativeEntryPointData::GetInlineeFrameOffsetArrayCount() 
+{ 
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    return this->inlineeFrameOffsetArrayCount; 
+}
+
+void
+OOPNativeEntryPointData::RecordInlineeFrameOffsetsInfo(unsigned int offsetsArrayOffset, unsigned int offsetsArrayCount)
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    this->inlineeFrameOffsetArrayOffset = offsetsArrayOffset;
+    this->inlineeFrameOffsetArrayCount = offsetsArrayCount;
+}
+
+#if !FLOATVAR
+void
+OOPNativeEntryPointData::ProcessNumberPageSegments(ScriptContext * scriptContext)
+{
+    if (this->numberPageSegments)
+    {
+        this->numberArray = scriptContext->GetThreadContext()
+            ->GetXProcNumberPageSegmentManager()->RegisterSegments(this->numberPageSegments);
+        this->numberPageSegments = nullptr;
+    }
+}
+#endif
+
+void
+OOPNativeEntryPointData::OnCleanup()
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    if (this->nativeDataBuffer)
+    {
+        DeleteNativeDataBuffer(this->nativeDataBuffer);
+        this->nativeDataBuffer = nullptr;
+    }
+
+#if !FLOATVAR
+    this->numberArray = nullptr;
+#endif
+}
+
+void
+OOPNativeEntryPointData::DeleteNativeDataBuffer(char * nativeDataBuffer)
+{
+    Assert(JITManager::GetJITManager()->IsOOPJITEnabled());
+    NativeDataBuffer* buffer = (NativeDataBuffer*)(nativeDataBuffer - offsetof(NativeDataBuffer, data));
+    midl_user_free(buffer);
+}
+
+#endif

+ 217 - 0
lib/Backend/NativeEntryPointData.h

@@ -0,0 +1,217 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+#pragma once
+
+#if ENABLE_NATIVE_CODEGEN
+class NativeCodeData;
+
+namespace Js
+{
+    class FunctionBody;
+};
+
+typedef JsUtil::List<NativeOffsetInlineeFramePair, HeapAllocator> InlineeFrameMap;
+typedef JsUtil::List<LazyBailOutRecord, HeapAllocator> BailOutRecordMap;
+
+class JitTransferData;
+
+class NativeEntryPointData
+{
+public:
+    NativeEntryPointData();
+    
+    JitTransferData* EnsureJitTransferData(Recycler* recycler);
+    JitTransferData* GetJitTransferData() { return this->jitTransferData; }    
+    void FreeJitTransferData();
+
+    void RecordNativeCode(Js::JavascriptMethod thunkAddress, Js::JavascriptMethod nativeAddress, ptrdiff_t codeSize, void * validationCookie);
+    Js::JavascriptMethod GetNativeAddress() { return this->nativeAddress; }
+    Js::JavascriptMethod GetThunkAddress() { return this->thunkAddress; }
+    ptrdiff_t GetCodeSize() { return this->codeSize; }
+
+    void SetTJNativeAddress(Js::JavascriptMethod nativeAddress, void * validationCookie);
+    void SetTJCodeSize(ptrdiff_t codeSize);
+
+    void AddWeakFuncRef(RecyclerWeakReference<Js::FunctionBody> *weakFuncRef, Recycler *recycler);
+
+    Js::EntryPointPolymorphicInlineCacheInfo * EnsurePolymorphicInlineCacheInfo(Recycler * recycler, Js::FunctionBody * functionBody);
+    Js::EntryPointPolymorphicInlineCacheInfo * GetPolymorphicInlineCacheInfo() { return polymorphicInlineCacheInfo; }
+
+    void RegisterConstructorCache(Js::ConstructorCache* constructorCache, Recycler* recycler);
+#if DBG
+    uint GetConstructorCacheCount() const { return this->constructorCaches != nullptr ? this->constructorCaches->Count() : 0; }
+#endif
+
+    void PinTypeRefs(Recycler * recycler, size_t count, void ** typeRefs);
+
+    Js::PropertyGuard* RegisterSharedPropertyGuard(Js::PropertyId propertyId, Js::ScriptContext* scriptContext);
+    Js::PropertyId* GetSharedPropertyGuards(Recycler * recycler, _Out_ unsigned int& count);
+    bool TryGetSharedPropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard*& guard);
+
+    Js::EquivalentTypeCache * EnsureEquivalentTypeCache(int guardCount, Js::ScriptContext * scriptContext, Js::EntryPointInfo * entryPointInfo);
+    bool ClearEquivalentTypeCaches(Recycler * recycler);
+
+    Field(Js::FakePropertyGuardWeakReference*) * EnsurePropertyGuardWeakRefs(int guardCount, Recycler * recycler);
+
+    Js::SmallSpanSequence * GetNativeThrowSpanSequence() { return this->nativeThrowSpanSequence; }
+    void SetNativeThrowSpanSequence(Js::SmallSpanSequence * seq) { this->nativeThrowSpanSequence = seq; }
+    uint GetFrameHeight() { return frameHeight; }
+    void SetFrameHeight(uint frameHeight) { this->frameHeight = frameHeight; }
+    uint32 GetPendingPolymorphicCacheState() const { return this->pendingPolymorphicCacheState; }
+    void SetPendingPolymorphicCacheState(uint32 state) { this->pendingPolymorphicCacheState = state; }
+    BYTE GetPendingInlinerVersion() const { return this->pendingInlinerVersion; }
+    void SetPendingInlinerVersion(BYTE version) { this->pendingInlinerVersion = version; }
+    Js::ImplicitCallFlags GetPendingImplicitCallFlags() const { return this->pendingImplicitCallFlags; }
+    void SetPendingImplicitCallFlags(Js::ImplicitCallFlags flags) { this->pendingImplicitCallFlags = flags; }
+   
+    void Cleanup(Js::ScriptContext * scriptContext, bool isShutdown, bool reset);
+    void ClearTypeRefsAndGuards(Js::ScriptContext * scriptContext);   
+
+#if PDATA_ENABLED
+    XDataAllocation* GetXDataInfo() { return this->xdataInfo; }
+    void SetXDataInfo(XDataAllocation* xdataInfo) { this->xdataInfo = xdataInfo; }   
+#endif
+private:
+    void RegisterEquivalentTypeCaches(Js::ScriptContext * scriptContext, Js::EntryPointInfo * entryPointInfo);
+    void UnregisterEquivalentTypeCaches(Js::ScriptContext * scriptContext);
+    void FreePropertyGuards();
+
+    void FreeNativeCode(Js::ScriptContext * scriptContext, bool isShutdown);
+#if PDATA_ENABLED
+    void CleanupXDataInfo();
+#endif
+
+    FieldNoBarrier(Js::JavascriptMethod) nativeAddress;
+    FieldNoBarrier(Js::JavascriptMethod) thunkAddress;
+    Field(ptrdiff_t) codeSize;
+    Field(void*) validationCookie;
+
+    // This field holds any recycler allocated references that must be kept alive until
+    // we install the entry point.  It is freed at that point, so anything that must survive
+    // until the EntryPointInfo itself goes away, must be copied somewhere else.
+    Field(JitTransferData*) jitTransferData;
+
+    typedef JsUtil::BaseHashSet<RecyclerWeakReference<Js::FunctionBody>*, Recycler, PowerOf2SizePolicy> WeakFuncRefSet;
+    Field(WeakFuncRefSet *) weakFuncRefSet;
+
+    // Need to keep strong references to the guards here so they don't get collected while the entry point is alive.
+    typedef JsUtil::BaseDictionary<Js::PropertyId, Js::PropertyGuard*, Recycler, PowerOf2SizePolicy> SharedPropertyGuardDictionary;
+    Field(SharedPropertyGuardDictionary*) sharedPropertyGuards;
+
+    typedef SListCounted<Js::ConstructorCache*, Recycler> ConstructorCacheList;
+    Field(ConstructorCacheList*) constructorCaches;
+
+    Field(Js::EntryPointPolymorphicInlineCacheInfo *) polymorphicInlineCacheInfo;
+
+    // If we pin types this array contains strong references to types, otherwise it holds weak references.
+    Field(Field(void*)*) runtimeTypeRefs;
+
+    // This array holds fake weak references to type property guards. We need it to zero out the weak references when the
+    // entry point is finalized and the guards are about to be freed. Otherwise, if one of the guards was to be invalidated
+    // from the thread context, we would AV trying to access freed memory. Note that the guards themselves are allocated by
+    // NativeCodeData::Allocator and are kept alive by the data field. The weak references are recycler allocated, and so
+    // the array must be recycler allocated also, so that the recycler doesn't collect the weak references.
+    Field(Field(Js::FakePropertyGuardWeakReference*)*) propertyGuardWeakRefs;
+    Field(Js::EquivalentTypeCache*) equivalentTypeCaches;
+    Field(Js::EntryPointInfo **) registeredEquivalentTypeCacheRef;
+
+    FieldNoBarrier(Js::SmallSpanSequence *) nativeThrowSpanSequence;
+
+#if PDATA_ENABLED
+    Field(XDataAllocation *) xdataInfo;
+#endif
+
+    Field(int) propertyGuardCount;
+    Field(int) equivalentTypeCacheCount;
+
+    Field(uint) frameHeight;
+
+    // TODO: these only applies to FunctionEntryPointInfo
+    Field(BYTE)                pendingInlinerVersion;
+    Field(Js::ImplicitCallFlags) pendingImplicitCallFlags;
+    Field(uint32)              pendingPolymorphicCacheState;
+
+#if DBG_DUMP || defined(VTUNE_PROFILING)    
+public:
+    // NativeOffsetMap is public for DBG_DUMP, private for VTUNE_PROFILING
+    struct NativeOffsetMap
+    {
+        uint32 statementIndex;
+        regex::Interval nativeOffsetSpan;
+    };
+    typedef JsUtil::List<NativeOffsetMap, HeapAllocator> NativeOffsetMapListType;
+    NativeOffsetMapListType& GetNativeOffsetMaps() { return nativeOffsetMaps; }
+private:    
+    Field(NativeOffsetMapListType) nativeOffsetMaps;
+#endif
+};
+
+class InProcNativeEntryPointData : public NativeEntryPointData
+{
+public:
+    InProcNativeEntryPointData();
+
+    void SetNativeCodeData(NativeCodeData * nativeCodeData);
+
+    InlineeFrameMap * GetInlineeFrameMap();
+    void RecordInlineeFrameMap(JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator>* tempInlineeFrameMap);
+
+    BailOutRecordMap * GetBailOutRecordMap();
+    void RecordBailOutMap(JsUtil::List<LazyBailOutRecord, ArenaAllocator>* bailoutMap);
+
+#if !FLOATVAR
+    void SetNumberChunks(CodeGenNumberChunk* chunks)
+    {
+        numberChunks = chunks;
+    }
+#endif
+    void OnCleanup();
+private:
+    FieldNoBarrier(NativeCodeData *) nativeCodeData;
+    FieldNoBarrier(InlineeFrameMap*) inlineeFrameMap;
+    FieldNoBarrier(BailOutRecordMap*) bailoutRecordMap;
+#if !FLOATVAR
+    Field(CodeGenNumberChunk*) numberChunks;
+#endif
+};
+
+class OOPNativeEntryPointData : public NativeEntryPointData
+{
+public:
+    OOPNativeEntryPointData();
+
+    static uint32 GetOffsetOfNativeDataBuffer();
+    static void DeleteNativeDataBuffer(char * naitveDataBuffer);
+
+    char* GetNativeDataBuffer();
+    char** GetNativeDataBufferRef();
+    void SetNativeDataBuffer(char *);
+
+    uint GetInlineeFrameOffsetArrayOffset();
+    uint GetInlineeFrameOffsetArrayCount();
+    void RecordInlineeFrameOffsetsInfo(unsigned int offsetsArrayOffset, unsigned int offsetsArrayCount);
+
+#if !FLOATVAR
+    void ProcessNumberPageSegments(Js::ScriptContext * scriptContext);
+    void SetNumberPageSegment(XProcNumberPageSegment * segments)
+    {
+        Assert(numberPageSegments == nullptr);
+        numberPageSegments = segments;
+    }
+#endif
+
+    void OnCleanup();
+private:
+    Field(uint) inlineeFrameOffsetArrayOffset;
+    Field(uint) inlineeFrameOffsetArrayCount;
+    FieldNoBarrier(char *) nativeDataBuffer;
+
+#if !FLOATVAR
+    Field(Field(Js::JavascriptNumber*)*) numberArray;
+    Field(XProcNumberPageSegment*) numberPageSegments;
+#endif
+};
+
+#endif

+ 7 - 5
lib/Backend/ObjTypeSpecFldInfo.cpp

@@ -4,6 +4,8 @@
 //-------------------------------------------------------------------------------------------------------
 
 #include "Backend.h"
+#include "NativeEntryPointData.h"
+#include "JitTransferData.h"
 
 CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(ObjTypeSpecFldInfo));
 
@@ -336,7 +338,7 @@ ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::InlineCache* cac
             // These shared property guards are registered on the main thread and checked during entry point installation
             // (see NativeCodeGenerator::CheckCodeGenDone) to ensure that no property became read-only while we were
             // JIT-ing on the background thread.
-            propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+            propertyGuard = entryPoint->GetNativeEntryPointData()->RegisterSharedPropertyGuard(propertyId, scriptContext);
         }
     }
     else if (isProto)
@@ -353,7 +355,7 @@ ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::InlineCache* cac
             fieldValue = prototypeObject->GetInlineSlot(slotIndex);
         }
         isMissing = localCache.u.proto.isMissing;
-        propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+        propertyGuard = entryPoint->GetNativeEntryPointData()->RegisterSharedPropertyGuard(propertyId, scriptContext);
     }
     else
     {
@@ -411,7 +413,7 @@ ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::InlineCache* cac
 
             if (fixedProperty != nullptr && propertyGuard == nullptr)
             {
-                propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+                propertyGuard = entryPoint->GetNativeEntryPointData()->RegisterSharedPropertyGuard(propertyId, scriptContext);
             }
 
             if (fixedProperty != nullptr && Js::JavascriptFunction::Is(fixedProperty))
@@ -487,7 +489,7 @@ ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::InlineCache* cac
                     }
 
                     // We must keep the runtime cache alive as long as this entry point exists and may try to dereference it.
-                    entryPoint->RegisterConstructorCache(runtimeConstructorCache, recycler);
+                    entryPoint->GetNativeEntryPointData()->RegisterConstructorCache(runtimeConstructorCache, recycler);
                     ctorCache = RecyclerNew(recycler, JITTimeConstructorCache, functionObject, runtimeConstructorCache);
 
                     if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
@@ -902,7 +904,7 @@ ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::PolymorphicInlin
     }
 
     Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(cacheId);
-    Js::PropertyGuard* propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+    Js::PropertyGuard* propertyGuard = entryPoint->GetNativeEntryPointData()->RegisterSharedPropertyGuard(propertyId, scriptContext);
 
     // For polymorphic, non-equivalent objTypeSpecFldInfo's, hasFixedValue is true only if each of the inline caches has a fixed function for the given cacheId, or
     // in the case of an accessor cache, only if the there is only one version of the accessor.

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

@@ -1546,7 +1546,7 @@ EncoderMD::FixMaps(uint32 brOffset, uint32 bytesSaved, uint32 *inlineeFrameRecor
 
 {
     InlineeFrameRecords *recList = m_encoder->m_inlineeFrameRecords;
-    InlineeFrameMap *mapList = m_encoder->m_inlineeFrameMap;
+    ArenaInlineeFrameMap *mapList = m_encoder->m_inlineeFrameMap;
     PragmaInstrList *pInstrList = m_encoder->m_pragmaInstrToRecordOffset;
     int32 i;
     for (i = *inlineeFrameRecordsIndex; i < recList->Count() && recList->Item(i)->inlineeStartOffset <= brOffset; i++)

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

@@ -1377,7 +1377,7 @@ EncoderMD::FixMaps(uint32 brOffset, int32 bytesSaved, uint32 *inlineeFrameRecord
 
 {
     InlineeFrameRecords *recList = m_encoder->m_inlineeFrameRecords;
-    InlineeFrameMap *mapList = m_encoder->m_inlineeFrameMap;
+    ArenaInlineeFrameMap *mapList = m_encoder->m_inlineeFrameMap;
     PragmaInstrList *pInstrList = m_encoder->m_pragmaInstrToRecordOffset;
     int32 i;
     for (i = *inlineeFrameRecordsIndex; i < recList->Count() && recList->Item(i)->inlineeStartOffset <= brOffset; i++)

+ 1 - 0
lib/Common/CommonDefines.h

@@ -524,6 +524,7 @@
 
 #ifdef DBG
 #define VALIDATE_ARRAY
+#define ENABLE_ENTRYPOINT_CLEANUP_TRACE 1
 
 // xplat-todo: Do we need dump generation for non-Win32 platforms?
 #ifdef _WIN32

+ 2 - 2
lib/Runtime/Base/Chakra.Runtime.Base.vcxproj

@@ -52,7 +52,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionExecutionStateMachine.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)LeaveScriptObject.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)LineOffsetCache.cpp" />    
+    <ClCompile Include="$(MSBuildThisFileDirectory)LineOffsetCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)PerfHint.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)PropertyRecord.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ScriptContext.cpp" />
@@ -136,4 +136,4 @@
   </ItemGroup>
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-</Project>
+</Project>

+ 26 - 6
lib/Runtime/Base/ExpirableObject.cpp

@@ -5,8 +5,7 @@
 #include "RuntimeBasePch.h"
 
 ExpirableObject::ExpirableObject(ThreadContext* threadContext):
-    isUsed(false),
-    registrationHandle(nullptr)
+    registrationHandle(0)
 {
     if (threadContext)
     {
@@ -16,7 +15,7 @@ ExpirableObject::ExpirableObject(ThreadContext* threadContext):
 
 void ExpirableObject::Finalize(bool isShutdown)
 {
-    if (!isShutdown && this->registrationHandle != nullptr)
+    if (!isShutdown && this->GetRegistrationHandle() != nullptr)
     {
         ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
 
@@ -28,17 +27,38 @@ void ExpirableObject::Dispose(bool isShutdown)
 {
 }
 
+void * ExpirableObject::GetRegistrationHandle()
+{
+    return (void *)(registrationHandle & ~1);
+}
+
+void 
+ExpirableObject::SetRegistrationHandle(void * registrationHandle)
+{
+    Assert(this->GetRegistrationHandle() == nullptr);
+    Assert(((intptr_t)registrationHandle & 1) == 0);
+    Assert(registrationHandle != nullptr);
+    this->registrationHandle |= (intptr_t)registrationHandle;
+}
+
+void
+ExpirableObject::ClearRegistrationHandle()
+{
+    Assert(this->GetRegistrationHandle() != nullptr);
+    this->registrationHandle = this->registrationHandle & 1;
+}
+
 void ExpirableObject::EnterExpirableCollectMode()
 {
-    this->isUsed = false;
+    this->registrationHandle &= ~1;
 }
 
 bool ExpirableObject::IsObjectUsed()
 {
-    return this->isUsed;
+    return (this->registrationHandle & 1);
 }
 
 void ExpirableObject::SetIsObjectUsed()
 {
-    this->isUsed = true;
+    this->registrationHandle |= 1;
 }

+ 6 - 4
lib/Runtime/Base/ExpirableObject.h

@@ -7,7 +7,6 @@ class ThreadContext;
 class ExpirableObject: public FinalizableObject
 {
 public:
-    friend class ThreadContext;
     ExpirableObject(ThreadContext* threadContext);
 
     virtual void Finalize(bool isShutdown);
@@ -24,10 +23,13 @@ public:
     void SetIsObjectUsed();
     bool SupportsExpiration()
     {
-        return (registrationHandle != nullptr);
+        return (GetRegistrationHandle() != nullptr);
     }
 
+    // Used by ThreadContext
+    void * GetRegistrationHandle();
+    void SetRegistrationHandle(void * registrationHandle);
+    void ClearRegistrationHandle();
 private:
-    Field(void*) registrationHandle;
-    Field(bool) isUsed;
+    Field(intptr_t) registrationHandle;
 };

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 275 - 325
lib/Runtime/Base/FunctionBody.cpp


+ 70 - 375
lib/Runtime/Base/FunctionBody.h

@@ -13,7 +13,6 @@
 struct CodeGenWorkItem;
 class SourceContextInfo;
 struct DeferredFunctionStub;
-struct CodeGenNumberChunk;
 #ifdef DYNAMIC_PROFILE_MUTATOR
 class DynamicProfileMutator;
 class DynamicProfileMutatorImpl;
@@ -22,6 +21,15 @@ class DynamicProfileMutatorImpl;
 
 typedef BVSparse<ArenaAllocator> ActiveFunctionSet;
 
+#if ENABLE_NATIVE_CODEGEN
+class JitTransferData;
+class NativeEntryPointData;
+class InProcNativeEntryPointData;
+#if ENABLE_OOP_NATIVE_CODEGEN
+class OOPNativeEntryPointData;
+#endif
+#endif
+
 namespace Js
 {
 #pragma region Class Forward Declarations
@@ -58,8 +66,6 @@ namespace Js
     class JavascriptNumber;
 #pragma endregion
 
-    typedef JsUtil::BaseHashSet<void*, Recycler, PowerOf2SizePolicy> TypeRefSet;
-
      // Definition of scopes such as With, Catch and Block which will be used further in the debugger for additional look-ups.
     enum DiagExtraScopesType
     {
@@ -211,26 +217,12 @@ namespace Js
         virtual bool IsFunctionEntryPointInfo() const { return false; }
     };
 
-
-    struct TypeGuardTransferData
-    {
-        Field(unsigned int) propertyGuardCount;
-        FieldNoBarrier(TypeGuardTransferEntryIDL*) entries;
-    };
-
-    struct CtorCacheTransferData
-    {
-        Field(unsigned int) ctorCachesCount;
-        FieldNoBarrier(CtorCacheTransferEntryIDL **) entries;
-    };
-
-
-
     // Not thread safe.
     // Note that instances of this class are read from and written to from the
     // main and JIT threads.
     class EntryPointInfo : public ProxyEntryPointInfo
     {
+        
     private:
         enum State : BYTE
         {
@@ -249,167 +241,20 @@ namespace Js
         Field(bool)                isLoopBody : 1;
         Field(bool)                hasJittedStackClosure : 1;
         Field(bool)                isAsmJsFunction : 1; // true if entrypoint is for asmjs function
+        Field(bool)                nativeEntryPointProcessed : 1;
+        Field(bool)                mIsTemplatizedJitMode : 1; // true only if in TJ mode, used only for debugging
         Field(State)               state; // Single state member so users can query state w/o a lock
 #if ENABLE_NATIVE_CODEGEN
-        Field(BYTE)                pendingInlinerVersion;
-        Field(ImplicitCallFlags)   pendingImplicitCallFlags;
-        Field(uint32)              pendingPolymorphicCacheState;
-
-        class JitTransferData
-        {
-            friend EntryPointInfo;
-
-        private:
-            Field(TypeRefSet*) jitTimeTypeRefs;
-
-            Field(PinnedTypeRefsIDL*) runtimeTypeRefs;
-
-
-            Field(int) propertyGuardCount;
-            // This is a dynamically sized array of dynamically sized TypeGuardTransferEntries.  It's heap allocated by the JIT
-            // thread and lives until entry point is installed, at which point it is explicitly freed.
-            FieldNoBarrier(TypeGuardTransferEntry*) propertyGuardsByPropertyId;
-            Field(size_t) propertyGuardsByPropertyIdPlusSize;
-
-            // This is a dynamically sized array of dynamically sized CtorCacheGuardTransferEntry.  It's heap allocated by the JIT
-            // thread and lives until entry point is installed, at which point it is explicitly freed.
-            FieldNoBarrier(CtorCacheGuardTransferEntry*) ctorCacheGuardsByPropertyId;
-            Field(size_t) ctorCacheGuardsByPropertyIdPlusSize;
-
-            Field(int) equivalentTypeGuardCount;
-            Field(int) lazyBailoutPropertyCount;
-            // This is a dynamically sized array of JitEquivalentTypeGuards. It's heap allocated by the JIT thread and lives
-            // until entry point is installed, at which point it is explicitly freed. We need it during installation so as to
-            // swap the cache associated with each guard from the heap to the recycler (so the types in the cache are kept alive).
-            FieldNoBarrier(JitEquivalentTypeGuard**) equivalentTypeGuards;
-            FieldNoBarrier(Js::PropertyId*) lazyBailoutProperties;
-            FieldNoBarrier(NativeCodeData*) jitTransferRawData;
-            FieldNoBarrier(EquivalentTypeGuardOffsets*) equivalentTypeGuardOffsets;
-            Field(TypeGuardTransferData) typeGuardTransferData;
-            Field(CtorCacheTransferData) ctorCacheTransferData;
-
-            Field(bool) falseReferencePreventionBit;
-            Field(bool) isReady;
-
-        public:
-            JitTransferData():
-                jitTimeTypeRefs(nullptr), runtimeTypeRefs(nullptr),
-                propertyGuardCount(0), propertyGuardsByPropertyId(nullptr), propertyGuardsByPropertyIdPlusSize(0),
-                ctorCacheGuardsByPropertyId(nullptr), ctorCacheGuardsByPropertyIdPlusSize(0),
-                equivalentTypeGuardCount(0), equivalentTypeGuards(nullptr), jitTransferRawData(nullptr),
-                falseReferencePreventionBit(true), isReady(false), lazyBailoutProperties(nullptr), lazyBailoutPropertyCount(0){}
-
-            void SetRawData(NativeCodeData* rawData) { jitTransferRawData = rawData; }
-            void AddJitTimeTypeRef(void* typeRef, Recycler* recycler);
-
-            int GetRuntimeTypeRefCount() { return this->runtimeTypeRefs ? this->runtimeTypeRefs->count : 0; }
-            void** GetRuntimeTypeRefs() { return this->runtimeTypeRefs ? (void**)this->runtimeTypeRefs->typeRefs : nullptr; }
-            void SetRuntimeTypeRefs(PinnedTypeRefsIDL* pinnedTypeRefs) { this->runtimeTypeRefs = pinnedTypeRefs;}
-
-            JitEquivalentTypeGuard** GetEquivalentTypeGuards() const { return this->equivalentTypeGuards; }
-            void SetEquivalentTypeGuards(JitEquivalentTypeGuard** guards, int count)
-            {
-                this->equivalentTypeGuardCount = count;
-                this->equivalentTypeGuards = guards;
-            }
-            void SetLazyBailoutProperties(Js::PropertyId* properties, int count)
-            {
-                this->lazyBailoutProperties = properties;
-                this->lazyBailoutPropertyCount = count;
-            }
-            void SetEquivalentTypeGuardOffsets(EquivalentTypeGuardOffsets* offsets)
-            {
-                equivalentTypeGuardOffsets = offsets;
-            }
-            void SetTypeGuardTransferData(JITOutputIDL* data)
-            {
-                typeGuardTransferData.entries = data->typeGuardEntries;
-                typeGuardTransferData.propertyGuardCount = data->propertyGuardCount;
-            }
-            void SetCtorCacheTransferData(JITOutputIDL * data)
-            {
-                ctorCacheTransferData.entries = data->ctorCacheEntries;
-                ctorCacheTransferData.ctorCachesCount = data->ctorCachesCount;
-            }
-            bool GetIsReady() { return this->isReady; }
-            void SetIsReady() { this->isReady = true; }
-
-        private:
-            void EnsureJitTimeTypeRefs(Recycler* recycler);
-        };
-
-        Field(NativeCodeData *) inProcJITNaticeCodedata;
-        FieldNoBarrier(char*) nativeDataBuffer;
-#if !FLOATVAR
-        union
-        {
-            Field(Field(JavascriptNumber*)*) numberArray;
-            Field(CodeGenNumberChunk*) numberChunks;
-        };
-        Field(XProcNumberPageSegment*) numberPageSegments;
-#endif
-
-        FieldNoBarrier(SmallSpanSequence *) nativeThrowSpanSequence;
-        typedef JsUtil::BaseHashSet<RecyclerWeakReference<FunctionBody>*, Recycler, PowerOf2SizePolicy> WeakFuncRefSet;
-        Field(WeakFuncRefSet *) weakFuncRefSet;
-        // Need to keep strong references to the guards here so they don't get collected while the entry point is alive.
-        typedef JsUtil::BaseDictionary<Js::PropertyId, PropertyGuard*, Recycler, PowerOf2SizePolicy> SharedPropertyGuardDictionary;
-        Field(SharedPropertyGuardDictionary*) sharedPropertyGuards;
-        typedef JsUtil::List<LazyBailOutRecord, HeapAllocator> BailOutRecordMap;
-        Field(BailOutRecordMap*) bailoutRecordMap;
-
-        // This array holds fake weak references to type property guards. We need it to zero out the weak references when the
-        // entry point is finalized and the guards are about to be freed. Otherwise, if one of the guards was to be invalidated
-        // from the thread context, we would AV trying to access freed memory. Note that the guards themselves are allocated by
-        // NativeCodeData::Allocator and are kept alive by the data field. The weak references are recycler allocated, and so
-        // the array must be recycler allocated also, so that the recycler doesn't collect the weak references.
-        Field(Field(FakePropertyGuardWeakReference*)*) propertyGuardWeakRefs;
-        Field(EquivalentTypeCache*) equivalentTypeCaches;
-        Field(EntryPointInfo **) registeredEquivalentTypeCacheRef;
-
-        Field(int) propertyGuardCount;
-        Field(int) equivalentTypeCacheCount;
-
-        Field(uint) inlineeFrameOffsetArrayOffset;
-        Field(uint) inlineeFrameOffsetArrayCount;
-
-        typedef SListCounted<ConstructorCache*, Recycler> ConstructorCacheList;
-        Field(ConstructorCacheList*) constructorCaches;
-
-        Field(EntryPointPolymorphicInlineCacheInfo *) polymorphicInlineCacheInfo;
-
-        // This field holds any recycler allocated references that must be kept alive until
-        // we install the entry point.  It is freed at that point, so anything that must survive
-        // until the EntryPointInfo itself goes away, must be copied somewhere else.
-        Field(JitTransferData*) jitTransferData;
-
-        // If we pin types this array contains strong references to types, otherwise it holds weak references.
-        Field(Field(void*)*) runtimeTypeRefs;
-     protected:
-#if PDATA_ENABLED
-        Field(XDataAllocation *) xdataInfo;
-#endif
+        Field(NativeEntryPointData *) nativeEntryPointData;
 #endif // ENABLE_NATIVE_CODEGEN
-
-        Field(CodeGenWorkItem *) workItem;
-        FieldNoBarrier(Js::JavascriptMethod) nativeAddress;
-        FieldNoBarrier(Js::JavascriptMethod) thunkAddress;
-        Field(ptrdiff_t) codeSize;
-
     protected:
+        Field(CodeGenWorkItem *) workItem;
         Field(JavascriptLibrary*) library;
-#if ENABLE_NATIVE_CODEGEN
-        typedef JsUtil::List<NativeOffsetInlineeFramePair, HeapAllocator> InlineeFrameMap;
-        Field(InlineeFrameMap*)   inlineeFrameMap;
-#endif
+
+#if ENABLE_ENTRYPOINT_CLEANUP_TRACE
 #if ENABLE_DEBUG_STACK_BACK_TRACE
         FieldNoBarrier(StackBackTrace*) cleanupStack;  // NoCheckHeapAllocator
 #endif
-    public:
-        Field(uint) frameHeight;
-        Field(bool) nativeEntryPointProcessed;
-
-#if ENABLE_DEBUG_CONFIG_OPTIONS
     public:
         enum CleanupReason
         {
@@ -424,7 +269,7 @@ namespace Js
         };
     private:
         Field(CleanupReason) cleanupReason;
-#endif
+#endif // ENABLE_ENTRYPOINT_CLEANUP_TRACE
 
 #ifdef FIELD_ACCESS_STATS
     private:
@@ -454,54 +299,29 @@ namespace Js
         virtual bool IsFunctionEntryPointInfo() const override { return true; }
 
 #if ENABLE_NATIVE_CODEGEN
-        char** GetNativeDataBufferRef() { return &nativeDataBuffer; }
-        char* GetNativeDataBuffer() { return nativeDataBuffer; }
-        void SetInProcJITNativeCodeData(NativeCodeData* nativeCodeData) { inProcJITNaticeCodedata = nativeCodeData; }
-#if !FLOATVAR
-        void SetNumberChunks(CodeGenNumberChunk* chunks)
-        {
-            Assert(numberPageSegments == nullptr);
-            numberChunks = chunks;
-        }
-        void SetNumberArray(Field(Js::JavascriptNumber*)* array)
-        {
-            Assert(numberPageSegments != nullptr);
-            numberArray = array;
-        }
-        void SetNumberPageSegment(XProcNumberPageSegment * segments)
-        {
-            Assert(numberPageSegments == nullptr);
-            numberPageSegments = segments;
-        }
+        NativeEntryPointData * EnsureNativeEntryPointData();
+        bool HasNativeEntryPointData() const;
+        NativeEntryPointData * GetNativeEntryPointData() const;
+        InProcNativeEntryPointData * GetInProcNativeEntryPointData();
+#if ENABLE_OOP_NATIVE_CODEGEN
+        OOPNativeEntryPointData * GetOOPNativeEntryPointData();
 #endif
 #endif
 
     protected:
-        EntryPointInfo(Js::JavascriptMethod method, JavascriptLibrary* library, void* validationCookie, ThreadContext* context = nullptr, bool isLoopBody = false) :
-            ProxyEntryPointInfo(method, context), tag(1), nativeEntryPointProcessed(false),
+        EntryPointInfo(Js::JavascriptMethod method, JavascriptLibrary* library, ThreadContext* context = nullptr, bool isLoopBody = false) :
+            ProxyEntryPointInfo(method, context), tag(1), nativeEntryPointProcessed(false), mIsTemplatizedJitMode(false),
 #if ENABLE_NATIVE_CODEGEN
-            nativeThrowSpanSequence(nullptr), workItem(nullptr), weakFuncRefSet(nullptr),
-            jitTransferData(nullptr), sharedPropertyGuards(nullptr), propertyGuardCount(0), propertyGuardWeakRefs(nullptr),
-            equivalentTypeCacheCount(0), equivalentTypeCaches(nullptr), constructorCaches(nullptr), state(NotScheduled), inProcJITNaticeCodedata(nullptr),
-#if !FLOATVAR
-            numberChunks(nullptr), numberPageSegments(nullptr), 
-#endif
-            polymorphicInlineCacheInfo(nullptr), runtimeTypeRefs(nullptr),
-            isLoopBody(isLoopBody), hasJittedStackClosure(false), registeredEquivalentTypeCacheRef(nullptr), bailoutRecordMap(nullptr), inlineeFrameMap(nullptr),
-#if PDATA_ENABLED
-            xdataInfo(nullptr),
+            nativeEntryPointData(nullptr), workItem(nullptr), state(NotScheduled),
+            isLoopBody(isLoopBody), hasJittedStackClosure(false),
 #endif
-#endif
-            library(library), codeSize(0), nativeAddress(nullptr), isAsmJsFunction(false), validationCookie(validationCookie)
+            library(library), isAsmJsFunction(false)
+#if ENABLE_ENTRYPOINT_CLEANUP_TRACE
 #if ENABLE_DEBUG_STACK_BACK_TRACE
             , cleanupStack(nullptr)
 #endif
-#if ENABLE_DEBUG_CONFIG_OPTIONS
             , cleanupReason(NotCleanedUp)
 #endif
-#if DBG_DUMP | defined(VTUNE_PROFILING)
-            , nativeOffsetMaps(&HeapAllocator::Instance)
-#endif
 #ifdef FIELD_ACCESS_STATS
             , fieldAccessStats(nullptr)
 #endif
@@ -526,15 +346,9 @@ namespace Js
 
         virtual FunctionBody *GetFunctionBody() const = 0;
 #if ENABLE_NATIVE_CODEGEN
-        EntryPointPolymorphicInlineCacheInfo * EnsurePolymorphicInlineCacheInfo(Recycler * recycler, FunctionBody * functionBody);
-        EntryPointPolymorphicInlineCacheInfo * GetPolymorphicInlineCacheInfo() { return polymorphicInlineCacheInfo; }
+        uint GetFrameHeight();
 
-        JitTransferData* GetJitTransferData() { return this->jitTransferData; }
-        JitTransferData* EnsureJitTransferData(Recycler* recycler);
-#if PDATA_ENABLED
-        XDataAllocation* GetXDataInfo() { return this->xdataInfo; }
-        void SetXDataInfo(XDataAllocation* xdataInfo) { this->xdataInfo = xdataInfo; }
-#endif
+        JitTransferData* GetJitTransferData();
 
 #ifdef FIELD_ACCESS_STATS
         FieldAccessStats* GetFieldAccessStats() { return this->fieldAccessStats; }
@@ -547,8 +361,10 @@ namespace Js
 
         void Cleanup(bool isShutdown, bool captureCleanupStack);
 
+#if ENABLE_ENTRYPOINT_CLEANUP_TRACE
 #if ENABLE_DEBUG_STACK_BACK_TRACE
         void CaptureCleanupStackTrace();
+#endif
 #endif
 
         bool IsNotScheduled() const
@@ -618,7 +434,7 @@ namespace Js
             this->state = PendingCleanup;
         }
 
-#if ENABLE_DEBUG_CONFIG_OPTIONS
+#if ENABLE_ENTRYPOINT_CLEANUP_TRACE
         void SetCleanupReason(CleanupReason reason)
         {
             this->cleanupReason = reason;
@@ -642,7 +458,7 @@ namespace Js
         }
 #endif
 
-        void Reset(bool resetStateToNotScheduled = true);
+        void Reset(bool resetStateToNotScheduled);
 
 #if ENABLE_NATIVE_CODEGEN
         void SetCodeGenPending(CodeGenWorkItem * workItem)
@@ -680,19 +496,7 @@ namespace Js
             this->state = CodeGenPending;
         }
 
-        void SetCodeGenRecorded(Js::JavascriptMethod thunkAddress, Js::JavascriptMethod nativeAddress, ptrdiff_t codeSize)
-        {
-            Assert(this->GetState() == CodeGenQueued);
-            Assert(codeSize > 0);
-            this->nativeAddress = nativeAddress;
-            this->thunkAddress = thunkAddress;
-            this->codeSize = codeSize;
-            this->state = CodeGenRecorded;
-
-#ifdef PERF_COUNTERS
-            this->OnRecorded();
-#endif
-        }
+        void SetCodeGenRecorded(Js::JavascriptMethod thunkAddress, Js::JavascriptMethod nativeAddress, ptrdiff_t codeSize, void * validationCookie);
 
         void SetCodeGenDone();
 
@@ -703,56 +507,20 @@ namespace Js
             this->workItem = nullptr;
         }
 
-        SmallSpanSequence* GetNativeThrowSpanSequence() const
-        {
-            Assert(this->GetState() != NotScheduled);
-            Assert(this->GetState() != CleanedUp);
-            return nativeThrowSpanSequence;
-        }
-
-        void SetNativeThrowSpanSequence(SmallSpanSequence* seq)
-        {
-            Assert(this->GetState() == CodeGenQueued);
-            Assert(this->nativeThrowSpanSequence == nullptr);
-
-            nativeThrowSpanSequence = seq;
-        }
+        SmallSpanSequence* GetNativeThrowSpanSequence() const;
+        void SetNativeThrowSpanSequence(SmallSpanSequence* seq);
 
         bool IsInNativeAddressRange(DWORD_PTR codeAddress) {
             return (IsNativeCode() &&
                 codeAddress >= GetNativeAddress() &&
                 codeAddress < GetNativeAddress() + GetCodeSize());
         }
-#endif
-
-        DWORD_PTR GetNativeAddress() const
-        {
-            // need the assert to skip for asmjsFunction as nativeAddress can be interpreter too for asmjs
-            Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone || this->isAsmJsFunction);
-
-            // !! this is illegal, however (by design) `IsInNativeAddressRange` (right above) needs it
-            return reinterpret_cast<DWORD_PTR>(this->nativeAddress);
-        }
-
-        Js::JavascriptMethod GetThunkAddress() const
-        {
-            Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone);
-
-            return this->thunkAddress;
-        }
-
-        Js::JavascriptMethod GetNativeEntrypoint() const
-        {
-            Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone || this->isAsmJsFunction);
-
-            return this->thunkAddress ? this->thunkAddress : this->nativeAddress;
-        }
 
-        ptrdiff_t GetCodeSize() const
-        {
-            Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone);
-            return codeSize;
-        }
+        DWORD_PTR GetNativeAddress() const;
+        Js::JavascriptMethod GetThunkAddress() const;
+        Js::JavascriptMethod GetNativeEntrypoint() const;
+        ptrdiff_t GetCodeSize() const;
+#endif
 
         CodeGenWorkItem * GetWorkItem() const
         {
@@ -771,119 +539,69 @@ namespace Js
 
 #ifdef ASMJS_PLAT
         // set code size, used by TJ to set the code size
-        void SetCodeSize(ptrdiff_t size)
-        {
-            Assert(isAsmJsFunction);
-            this->codeSize = size;
-        }
-
-        void SetNativeAddress(Js::JavascriptMethod address)
-        {
-            Assert(isAsmJsFunction);
-            this->nativeAddress = address;
-        }
+        void SetTJCodeSize(ptrdiff_t size);
+        void SetTJNativeAddress(Js::JavascriptMethod address, void * validationCookie);
 
         void SetIsAsmJSFunction(bool value)
         {
             this->isAsmJsFunction = value;
         }
-#endif
-
-        bool GetIsAsmJSFunction()const
-        {
-            return this->isAsmJsFunction;
-        }
 
-#ifdef ASMJS_PLAT
         void SetTJCodeGenDone()
         {
             Assert(isAsmJsFunction);
             this->state = CodeGenDone;
             this->workItem = nullptr;
         }
+
+        void SetIsTJMode(bool value);
+        bool GetIsTJMode() const;
 #endif
 
+        bool GetIsAsmJSFunction()const
+        {
+            return this->isAsmJsFunction;
+        }
+
 #if ENABLE_NATIVE_CODEGEN
-        void AddWeakFuncRef(RecyclerWeakReference<FunctionBody> *weakFuncRef, Recycler *recycler);
-        WeakFuncRefSet *EnsureWeakFuncRefSet(Recycler *recycler);
+        bool IsNativeEntryPointProcessed() { return this->nativeEntryPointProcessed; }
+        void SetNativeEntryPointProcessed() { this->nativeEntryPointProcessed = true; }
 
         void EnsureIsReadyToCall();
         void ProcessJitTransferData();
         void ResetOnLazyBailoutFailure();
         void OnNativeCodeInstallFailure();
         virtual void ResetOnNativeCodeInstallFailure() = 0;
+               
+        void FreeJitTransferData();        
+        bool ClearEquivalentTypeCaches();        
 
-        Js::PropertyGuard* RegisterSharedPropertyGuard(Js::PropertyId propertyId, ScriptContext* scriptContext);
-        Js::PropertyId* GetSharedPropertyGuards(_Out_ unsigned int& count);
-
-        bool TryGetSharedPropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard*& guard);
-        void RecordTypeGuards(int propertyGuardCount, TypeGuardTransferEntry* typeGuardTransferRecord, size_t typeGuardTransferPlusSize);
-        void RecordCtorCacheGuards(CtorCacheGuardTransferEntry* ctorCacheTransferRecord, size_t ctorCacheTransferPlusSize);
-        void FreePropertyGuards();
-        void FreeJitTransferData();
-        void RegisterEquivalentTypeCaches();
-        void UnregisterEquivalentTypeCaches();
-        bool ClearEquivalentTypeCaches();
-
-        void RegisterConstructorCache(Js::ConstructorCache* constructorCache, Recycler* recycler);
-        uint GetConstructorCacheCount() const { return this->constructorCaches != nullptr ? this->constructorCaches->Count() : 0; }
-        uint32 GetPendingPolymorphicCacheState() const { return this->pendingPolymorphicCacheState; }
-        void SetPendingPolymorphicCacheState(uint32 state) { this->pendingPolymorphicCacheState = state; }
-        BYTE GetPendingInlinerVersion() const { return this->pendingInlinerVersion; }
-        void SetPendingInlinerVersion(BYTE version) { this->pendingInlinerVersion = version; }
-        ImplicitCallFlags GetPendingImplicitCallFlags() const { return this->pendingImplicitCallFlags; }
-        void SetPendingImplicitCallFlags(ImplicitCallFlags flags) { this->pendingImplicitCallFlags = flags; }
         virtual void Invalidate(bool prolongEntryPoint) { Assert(false); }
-        void RecordBailOutMap(JsUtil::List<LazyBailOutRecord, ArenaAllocator>* bailoutMap);
-        void RecordInlineeFrameMap(JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator>* tempInlineeFrameMap);
-        void RecordInlineeFrameOffsetsInfo(unsigned int offsetsArrayOffset, unsigned int offsetsArrayCount);
         InlineeFrameRecord* FindInlineeFrame(void* returnAddress);
-        bool HasInlinees() { return this->frameHeight > 0; }
+        bool HasInlinees();
         void DoLazyBailout(BYTE** addressOfReturnAddress, Js::FunctionBody* functionBody, const PropertyRecord* propertyRecord);
-#endif
+
+        void CleanupNativeCode(ScriptContext * scriptContext);
 #if DBG_DUMP
     public:
 #elif defined(VTUNE_PROFILING)
     private:
 #endif
 #if DBG_DUMP || defined(VTUNE_PROFILING)
-        // NativeOffsetMap is public for DBG_DUMP, private for VTUNE_PROFILING
-        struct NativeOffsetMap
-        {
-            uint32 statementIndex;
-            regex::Interval nativeOffsetSpan;
-        };
-
-    private:
-        typedef JsUtil::List<NativeOffsetMap, HeapAllocator> NativeOffsetMapListType;
-        Field(NativeOffsetMapListType) nativeOffsetMaps;
     public:
         void RecordNativeMap(uint32 offset, uint32 statementIndex);
-
         int GetNativeOffsetMapCount() const;
 #endif
-
 #if DBG_DUMP && ENABLE_NATIVE_CODEGEN
         void DumpNativeOffsetMaps();
         void DumpNativeThrowSpanSequence();
-        NativeOffsetMap* GetNativeOffsetMap(int index)
-        {
-             Assert(index >= 0);
-             Assert(index < GetNativeOffsetMapCount());
-
-             return &nativeOffsetMaps.Item(index);
-        }
 #endif
-
 #ifdef VTUNE_PROFILING
-
     public:
         uint PopulateLineInfo(void* pLineInfo, FunctionBody* body);
-
 #endif
+#endif // ENABLE_NATIVE_CODEGEN
 
-    protected:
-        Field(void*) validationCookie;
     };
 
     class FunctionEntryPointInfo : public EntryPointInfo
@@ -903,15 +621,8 @@ namespace Js
 
     private:
         Field(ExecutionMode) jitMode;
-        Field(bool)       mIsTemplatizedJitMode; // true only if in TJ mode, used only for debugging
     public:
-        FunctionEntryPointInfo(FunctionProxy * functionInfo, Js::JavascriptMethod method, ThreadContext* context, void* validationCookie);
-
-#ifdef ASMJS_PLAT
-        void SetIsTJMode(bool value);
-        bool GetIsTJMode()const;
-        //End AsmJS Support
-#endif
+        FunctionEntryPointInfo(FunctionProxy * functionInfo, Js::JavascriptMethod method, ThreadContext* context);
 
         bool ExecutedSinceCallCountCollection() const;
         void CollectCallCounts();
@@ -947,12 +658,11 @@ namespace Js
         Field(LoopHeader*) loopHeader;
         Field(uint) jittedLoopIterationsSinceLastBailout; // number of times the loop iterated in the jitted code before bailing out
         Field(uint) totalJittedLoopIterations; // total number of times the loop has iterated in the jitted code for this entry point for a particular invocation of the loop
-        LoopEntryPointInfo(LoopHeader* loopHeader, Js::JavascriptLibrary* library, void* validationCookie) :
-            EntryPointInfo(nullptr, library, validationCookie, /*threadContext*/ nullptr, /*isLoopBody*/ true),
+        LoopEntryPointInfo(LoopHeader* loopHeader, Js::JavascriptLibrary* library) :
+            EntryPointInfo(nullptr, library, /*threadContext*/ nullptr, /*isLoopBody*/ true),
             loopHeader(loopHeader),
             jittedLoopIterationsSinceLastBailout(0),
-            totalJittedLoopIterations(0),
-            mIsTemplatizedJitMode(false)
+            totalJittedLoopIterations(0)
 #ifdef BGJIT_STATS
             ,used(false)
 #endif
@@ -970,19 +680,6 @@ namespace Js
         }
 #endif
 
-#ifdef ASMJS_PLAT
-        void SetIsTJMode(bool value)
-        {
-            Assert(this->GetIsAsmJSFunction());
-            mIsTemplatizedJitMode = value;
-        }
-
-        bool GetIsTJMode()const
-        {
-            return mIsTemplatizedJitMode;
-        };
-#endif
-
 #ifdef PERF_COUNTERS
         virtual void OnRecorded() override;
 #endif
@@ -997,12 +694,9 @@ namespace Js
         {
             this->used = true;
         }
-#endif
     private:
-#ifdef BGJIT_STATS
         Field(bool) used;
 #endif
-        Field(bool)       mIsTemplatizedJitMode;
     };
 
     typedef RecyclerWeakReference<FunctionEntryPointInfo> FunctionEntryPointWeakRef;
@@ -2439,7 +2133,7 @@ namespace Js
 #if DYNAMIC_INTERPRETER_THUNK
         void GenerateDynamicInterpreterThunk();
 #endif
-        void CloneByteCodeInto(ScriptContext * scriptContext, FunctionBody *newFunctionBody, uint sourceIndex);
+      
         Js::JavascriptMethod GetEntryPoint(ProxyEntryPointInfo* entryPoint) const { return entryPoint->jsMethod; }
         void CaptureDynamicProfileState(FunctionEntryPointInfo* entryPointInfo);
 #if ENABLE_DEBUG_CONFIG_OPTIONS
@@ -2915,9 +2609,9 @@ namespace Js
         JavascriptMethod EnsureDynamicInterpreterThunk(FunctionEntryPointInfo* entryPointInfo);
 #endif
 
+#if ENABLE_NATIVE_CODEGEN
         void SetCheckCodeGenEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint);
 
-#if ENABLE_NATIVE_CODEGEN
         typedef void (*SetNativeEntryPointFuncType)(FunctionEntryPointInfo* entryPointInfo, Js::FunctionBody * functionBody, Js::JavascriptMethod entryPoint);
         static void DefaultSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint);
         static void ProfileSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint);
@@ -3097,6 +2791,7 @@ namespace Js
         uint GetNumberOfRecursiveCallSites();
         bool CanInlineRecursively(uint depth, bool tryAggressive = true);
     public:
+#if ENABLE_NATIVE_CODEGEN
         bool CanInlineAgain() const
         {
             // Block excessive recursive inlining of the same function
@@ -3117,7 +2812,7 @@ namespace Js
         void ResetBailOnMisingProfileCount() { bailOnMisingProfileCount = 0; }
         uint8 IncrementBailOnMisingProfileRejitCount() { return ++bailOnMisingProfileRejitCount; }
         uint32 GetFrameHeight(EntryPointInfo* entryPointInfo) const;
-        void SetFrameHeight(EntryPointInfo* entryPointInfo, uint32 frameHeight);
+#endif
 
         RegSlot GetLocalsCount();
         RegSlot GetConstantCount() const { return this->GetCountField(CounterFields::ConstantCount); }

+ 5 - 5
lib/Runtime/Base/ThreadContext.cpp

@@ -2968,11 +2968,11 @@ void
 ThreadContext::RegisterExpirableObject(ExpirableObject* object)
 {
     Assert(this->expirableObjectList);
-    Assert(object->registrationHandle == nullptr);
+    Assert(object->GetRegistrationHandle() == nullptr);
 
     ExpirableObject** registrationData = this->expirableObjectList->PrependNode();
     (*registrationData) = object;
-    object->registrationHandle = (void*) registrationData;
+    object->SetRegistrationHandle((void*) registrationData);
     OUTPUT_VERBOSE_TRACE(Js::ExpirableCollectPhase, _u("Registered 0x%p\n"), object);
 
     numExpirableObjects++;
@@ -2982,13 +2982,13 @@ void
 ThreadContext::UnregisterExpirableObject(ExpirableObject* object)
 {
     Assert(this->expirableObjectList);
-    Assert(object->registrationHandle != nullptr);
+    Assert(object->GetRegistrationHandle() != nullptr);
 
-    ExpirableObject** registrationData = (ExpirableObject**)PointerValue(object->registrationHandle);
+    ExpirableObject** registrationData = (ExpirableObject**)PointerValue(object->GetRegistrationHandle());
     Assert(*registrationData == object);
 
     this->expirableObjectList->MoveElementTo(registrationData, this->expirableObjectDisposeList);
-    object->registrationHandle = nullptr;
+    object->ClearRegistrationHandle();
     OUTPUT_VERBOSE_TRACE(Js::ExpirableCollectPhase, _u("Unregistered 0x%p\n"), object);
     numExpirableObjects--;
 }

+ 1 - 1
lib/Runtime/Language/AsmJsCodeGenerator.cpp

@@ -33,7 +33,7 @@ namespace Js
             //set entrypointinfo address and nativeAddress with TJ address
             Js::JavascriptMethod method = reinterpret_cast<Js::JavascriptMethod>(address);
             entrypointInfo->jsMethod = method;
-            entrypointInfo->SetNativeAddress(method);
+            entrypointInfo->SetTJNativeAddress(method, mScriptContext->GetNativeCodeGenerator());
 #if ENABLE_DEBUG_CONFIG_OPTIONS
             funcEntrypointInfo->SetIsTJMode(true);
 #endif

+ 1 - 1
lib/Runtime/Language/AsmJsEncoder.cpp

@@ -254,7 +254,7 @@ namespace Js
                 functionBody->GetColumnNumber(),
                 functionBody->GetDisplayName()));
             entryPointInfo->SetTJCodeGenDone(); // set the codegen to done state for TJ
-            entryPointInfo->SetCodeSize(codeSize);
+            entryPointInfo->SetTJCodeSize(codeSize);
             return buffer;
         }
         return nullptr;

+ 1 - 1
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -5801,7 +5801,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(uint loopId)
 #endif
 
             entryPointInfo->EnsureIsReadyToCall();
-            entryPointInfo->nativeEntryPointProcessed = true;
+            entryPointInfo->SetNativeEntryPointProcessed();
 
             RegSlot envReg = this->m_functionBody->GetEnvRegister();
             if (envReg != Constants::NoRegister)

+ 1 - 1
lib/Runtime/Language/JavascriptStackWalker.cpp

@@ -1546,7 +1546,7 @@ namespace Js
 
         if (!StackFrame::IsInStackCheckCode(entry, codeAddr, stackCheckCodeHeight))
         {
-            inlinedFrame = (struct InlinedFrame *)(((uint8 *)framePointer) - entryPointInfo->frameHeight);
+            inlinedFrame = (struct InlinedFrame *)(((uint8 *)framePointer) - entryPointInfo->GetFrameHeight());
         }
 
         return inlinedFrame;

+ 0 - 7
lib/Runtime/Library/ScriptFunction.cpp

@@ -198,13 +198,6 @@ namespace Js
         return type;
     }
 
-    uint32 ScriptFunction::GetFrameHeight(FunctionEntryPointInfo* entryPointInfo) const
-    {
-        Assert(this->GetFunctionBody() != nullptr);
-
-        return this->GetFunctionBody()->GetFrameHeight(entryPointInfo);
-    }
-
     bool ScriptFunction::HasFunctionBody()
     {
         // for asmjs we want to first check if the FunctionObject has a function body. Check that the function is not deferred

+ 0 - 1
lib/Runtime/Library/ScriptFunction.h

@@ -88,7 +88,6 @@ namespace Js
         FunctionProxy * GetFunctionProxy() const;
         ScriptFunctionType * GetScriptFunctionType() const;
 
-        uint32 GetFrameHeight(FunctionEntryPointInfo* entryPointInfo) const;
         FrameDisplay* GetEnvironment() const { return environment; }
         void SetEnvironment(FrameDisplay * environment);
         ActivationObjectEx *GetCachedScope() const { return cachedScopeObj; }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels