Jelajahi Sumber

avoid extra redundant copying for obj type spec info

Michael Holman 9 tahun lalu
induk
melakukan
e164473208
38 mengubah file dengan 1452 tambahan dan 1818 penghapusan
  1. 3 4
      lib/Backend/Backend.h
  2. 1 1
      lib/Backend/BackwardPass.cpp
  3. 3 2
      lib/Backend/CMakeLists.txt
  4. 6 4
      lib/Backend/Chakra.Backend.vcxproj
  5. 6 3
      lib/Backend/Chakra.Backend.vcxproj.filters
  6. 95 0
      lib/Backend/FixedFieldInfo.cpp
  7. 5 2
      lib/Backend/FixedFieldInfo.h
  8. 4 4
      lib/Backend/Func.cpp
  9. 3 3
      lib/Backend/Func.h
  10. 2 2
      lib/Backend/FunctionCodeGenJitTimeData.cpp
  11. 0 0
      lib/Backend/FunctionCodeGenJitTimeData.h
  12. 8 18
      lib/Backend/FunctionJITTimeInfo.cpp
  13. 2 2
      lib/Backend/FunctionJITTimeInfo.h
  14. 1 1
      lib/Backend/GlobOpt.cpp
  15. 1 1
      lib/Backend/GlobOpt.h
  16. 1 1
      lib/Backend/GlobOptFields.cpp
  17. 2 2
      lib/Backend/IR.cpp
  18. 1 1
      lib/Backend/IR.h
  19. 8 8
      lib/Backend/Inline.cpp
  20. 2 2
      lib/Backend/Inline.h
  21. 0 337
      lib/Backend/JITObjTypeSpecFldInfo.cpp
  22. 0 70
      lib/Backend/JITObjTypeSpecFldInfo.h
  23. 0 63
      lib/Backend/JITTimeFixedField.cpp
  24. 1 0
      lib/Backend/JITType.cpp
  25. 4 4
      lib/Backend/Lower.cpp
  26. 12 10
      lib/Backend/NativeCodeGenerator.cpp
  27. 2 2
      lib/Backend/NativeCodeGenerator.h
  28. 1007 0
      lib/Backend/ObjTypeSpecFldInfo.cpp
  29. 258 0
      lib/Backend/ObjTypeSpecFldInfo.h
  30. 2 2
      lib/Backend/Opnd.cpp
  31. 7 7
      lib/Backend/Opnd.h
  32. 5 7
      lib/JITIDL/JITTypes.h
  33. 0 3
      lib/Runtime/Language/CMakeLists.txt
  34. 0 4
      lib/Runtime/Language/Chakra.Runtime.Language.vcxproj
  35. 0 4
      lib/Runtime/Language/Chakra.Runtime.Language.vcxproj.filters
  36. 0 828
      lib/Runtime/Language/ObjTypeSpecFldInfo.cpp
  37. 0 414
      lib/Runtime/Language/ObjTypeSpecFldInfo.h
  38. 0 2
      lib/Runtime/Language/RuntimeLanguagePch.h

+ 3 - 4
lib/Backend/Backend.h

@@ -16,8 +16,6 @@
 #include "Language/AsmJsModule.h"
 #include "Language/ProfilingHelpers.h"
 #include "Language/FunctionCodeGenRuntimeData.h"
-#include "Language/ObjTypeSpecFldInfo.h"
-#include "Language/FunctionCodeGenJitTimeData.h"
 #include "Language/JavascriptMathOperators.h"
 #include "Language/JavascriptMathOperators.inl"
 #include "Language/JavascriptStackWalker.h"
@@ -112,7 +110,7 @@ enum IRDumpFlags
 
 #include "JITTimeProfileInfo.h"
 #include "JITRecyclableObject.h"
-#include "JITTimeFixedField.h"
+#include "FixedFieldInfo.h"
 #include "JITTimePolymorphicInlineCache.h"
 #include "JITTimePolymorphicInlineCacheInfo.h"
 #include "CodeGenWorkItemType.h"
@@ -120,7 +118,8 @@ enum IRDumpFlags
 #include "JITTimeConstructorCache.h"
 #include "JITTypeHandler.h"
 #include "JITType.h"
-#include "JITObjTypeSpecFldInfo.h"
+#include "ObjTypeSpecFldInfo.h"
+#include "FunctionCodeGenJitTimeData.h"
 #include "ServerScriptContext.h"
 #include "JITOutput.h"
 #include "JITTimeScriptContext.h"

+ 1 - 1
lib/Backend/BackwardPass.cpp

@@ -4404,7 +4404,7 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
 #if DBG
         FOREACH_BITSET_IN_SPARSEBV(propOpId, guardedPropertyOps)
         {
-            JITObjTypeSpecFldInfo* existingFldInfo = this->func->GetGlobalObjTypeSpecFldInfo(propOpId);
+            ObjTypeSpecFldInfo* existingFldInfo = this->func->GetGlobalObjTypeSpecFldInfo(propOpId);
             Assert(existingFldInfo != nullptr);
 
             if (existingFldInfo->GetPropertyId() != opnd->GetPropertyId())

+ 3 - 2
lib/Backend/CMakeLists.txt

@@ -17,6 +17,7 @@ add_library (Chakra.Backend OBJECT
     Encoder.cpp
     FlowGraph.cpp
     Func.cpp
+    FunctionCodeGenJitTimeData.cpp
     FunctionJITRuntimeInfo.cpp
     FunctionJITTimeInfo.cpp
     GlobOpt.cpp
@@ -37,10 +38,9 @@ add_library (Chakra.Backend OBJECT
     InliningHeuristics.cpp
     IntBounds.cpp
     InterpreterThunkEmitter.cpp
-    JITObjTypeSpecFldInfo.cpp
     JITOutput.cpp
     JITTimeConstructorCache.cpp
-    JITTimeFixedField.cpp
+    FixedFieldInfo.cpp
     JITTimeFunctionBody.cpp
     JITTimePolymorphicInlineCache.cpp
     JITTimePolymorphicInlineCacheInfo.cpp
@@ -56,6 +56,7 @@ add_library (Chakra.Backend OBJECT
     LowerMDSharedSimd128.cpp
     NativeCodeData.cpp
     NativeCodeGenerator.cpp
+    ObjTypeSpecFldInfo.cpp
     Opnd.cpp
     PDataManager.cpp
     Peeps.cpp

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

@@ -204,7 +204,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)AsmJsJITInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionJITRuntimeInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionJITTimeInfo.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)JITObjTypeSpecFldInfo.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)ObjTypeSpecFldInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimeConstructorCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimePolymorphicInlineCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimePolymorphicInlineCacheInfo.cpp" />
@@ -212,7 +212,8 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTypeHandler.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerScriptContext.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerThreadContext.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)JITTimeFixedField.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)FixedFieldInfo.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)FunctionCodeGenJitTimeData.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AgenPeeps.h" />
@@ -250,6 +251,7 @@
       <ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
     </ClInclude>
     <ClInclude Include="AsmJsJITInfo.h" />
+    <ClInclude Include="FunctionCodeGenJitTimeData.h" />
     <ClInclude Include="FunctionJITRuntimeInfo.h" />
     <ClInclude Include="FunctionJITTimeInfo.h" />
     <ClInclude Include="IRBaseTypeList.h" />
@@ -384,11 +386,11 @@
     <ClInclude Include="IRViewer.h" />
     <ClInclude Include="IRType.h" />
     <ClInclude Include="IRTypeList.h" />
-    <ClInclude Include="JITObjTypeSpecFldInfo.h" />
+    <ClInclude Include="ObjTypeSpecFldInfo.h" />
     <ClInclude Include="JITOutput.h" />
     <ClInclude Include="JITRecyclableObject.h" />
     <ClInclude Include="JITTimeConstructorCache.h" />
-    <ClInclude Include="JITTimeFixedField.h" />
+    <ClInclude Include="FixedFieldInfo.h" />
     <ClInclude Include="JITTimeFunctionBody.h" />
     <ClInclude Include="JITTimePolymorphicInlineCache.h" />
     <ClInclude Include="JITTimePolymorphicInlineCacheInfo.h" />

+ 6 - 3
lib/Backend/Chakra.Backend.vcxproj.filters

@@ -117,7 +117,6 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)AsmJsJITInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionJITRuntimeInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionJITTimeInfo.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)JITObjTypeSpecFldInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimeConstructorCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimePolymorphicInlineCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimePolymorphicInlineCacheInfo.cpp" />
@@ -125,6 +124,9 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTypeHandler.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerScriptContext.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerThreadContext.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)FunctionCodeGenJitTimeData.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)FixedFieldInfo.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)ObjTypeSpecFldInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimeFixedField.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)PageAllocatorPool.cpp" />
   </ItemGroup>
@@ -326,7 +328,6 @@
     <ClInclude Include="AsmJsJITInfo.h" />
     <ClInclude Include="FunctionJITTimeInfo.h" />
     <ClInclude Include="FunctionJITRuntimeInfo.h" />
-    <ClInclude Include="JITObjTypeSpecFldInfo.h" />
     <ClInclude Include="JITTimeConstructorCache.h" />
     <ClInclude Include="JITType.h" />
     <ClInclude Include="JITTypeHandler.h" />
@@ -334,9 +335,11 @@
     <ClInclude Include="JITTimePolymorphicInlineCache.h" />
     <ClInclude Include="ServerThreadContext.h" />
     <ClInclude Include="ServerScriptContext.h" />
-    <ClInclude Include="JITTimeFixedField.h" />
     <ClInclude Include="ExternalLowerer.h" />
     <ClInclude Include="JITRecyclableObject.h" />
+    <ClInclude Include="FunctionCodeGenJitTimeData.h" />
+    <ClInclude Include="FixedFieldInfo.h" />
+    <ClInclude Include="ObjTypeSpecFldInfo.h" />
     <ClInclude Include="CRC.h" />
     <ClInclude Include="PageAllocatorPool.h" />
   </ItemGroup>

+ 95 - 0
lib/Backend/FixedFieldInfo.cpp

@@ -0,0 +1,95 @@
+//-------------------------------------------------------------------------------------------------------
+// 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"
+
+CompileAssert(sizeof(FixedFieldIDL) == sizeof(FixedFieldInfo));
+
+/* static */
+void
+FixedFieldInfo::PopulateFixedField(_In_opt_ Js::Type * type, _In_opt_ Js::Var var, _Out_ FixedFieldInfo * fixed)
+{
+    FixedFieldIDL * rawFF = fixed->GetRaw();
+    rawFF->fieldValue = (intptr_t)var;
+    rawFF->nextHasSameFixedField = false;
+    if (var != nullptr && Js::JavascriptFunction::Is(var))
+    {
+        Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(var);
+        rawFF->valueType = ValueType::FromObject(funcObj).GetRawData();
+        rawFF->funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
+        rawFF->isClassCtor = funcObj->GetFunctionInfo()->IsClassConstructor();
+        rawFF->localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
+        if (Js::ScriptFunction::Is(var))
+        {
+            rawFF->environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
+        }
+    }
+    if (type != nullptr)
+    {
+        JITType::BuildFromJsType(type, (JITType*)&rawFF->type);
+    }
+}
+
+void
+FixedFieldInfo::SetNextHasSameFixedField()
+{
+    m_data.nextHasSameFixedField = TRUE;
+}
+
+bool
+FixedFieldInfo::IsClassCtor() const
+{
+    return m_data.isClassCtor != FALSE;
+}
+
+bool
+FixedFieldInfo::NextHasSameFixedField() const
+{
+    return m_data.nextHasSameFixedField != FALSE;
+}
+
+uint
+FixedFieldInfo::GetLocalFuncId() const
+{
+    return m_data.localFuncId;
+}
+
+ValueType
+FixedFieldInfo::GetValueType() const
+{
+    CompileAssert(sizeof(ValueType) == sizeof(uint16));
+    return *(ValueType*)&m_data.valueType;
+}
+
+intptr_t
+FixedFieldInfo::GetFieldValue() const
+{
+    return m_data.fieldValue;
+}
+
+intptr_t
+FixedFieldInfo::GetFuncInfoAddr() const
+{
+    return m_data.funcInfoAddr;
+}
+
+intptr_t
+FixedFieldInfo::GetEnvironmentAddr() const
+{
+    return m_data.environmentAddr;
+}
+
+JITType *
+FixedFieldInfo::GetType() const
+{
+    return (JITType*)&m_data.type;
+}
+
+FixedFieldIDL *
+FixedFieldInfo::GetRaw()
+{
+    return &m_data;
+}
+

+ 5 - 2
lib/Backend/JITTimeFixedField.h → lib/Backend/FixedFieldInfo.h

@@ -5,9 +5,12 @@
 
 #pragma once
 
-class JITTimeFixedField
+class FixedFieldInfo
 {
 public:
+    FixedFieldInfo() {};
+    static void PopulateFixedField(_In_opt_ Js::Type * type, _In_opt_ Js::Var var, _Out_ FixedFieldInfo * fixed);
+
     void SetNextHasSameFixedField();
 
     bool IsClassCtor() const;
@@ -18,7 +21,7 @@ public:
     intptr_t GetEnvironmentAddr() const;
     intptr_t GetFieldValue() const;
     JITType * GetType() const;
+    FixedFieldIDL * GetRaw();
 private:
-    JITTimeFixedField();
     FixedFieldIDL m_data;
 };

+ 4 - 4
lib/Backend/Func.cpp

@@ -243,12 +243,12 @@ Func::Func(JitArenaAllocator *alloc, JITTimeWorkItem * workItem,
 
     if (this->IsTopFunc())
     {
-        m_globalObjTypeSpecFldInfoArray = JitAnewArrayZ(this->m_alloc, JITObjTypeSpecFldInfo*, GetWorkItem()->GetJITTimeInfo()->GetGlobalObjTypeSpecFldInfoCount());
+        m_globalObjTypeSpecFldInfoArray = JitAnewArrayZ(this->m_alloc, ObjTypeSpecFldInfo*, GetWorkItem()->GetJITTimeInfo()->GetGlobalObjTypeSpecFldInfoCount());
     }
 
     for (uint i = 0; i < GetJITFunctionBody()->GetInlineCacheCount(); ++i)
     {
-        JITObjTypeSpecFldInfo * info = GetWorkItem()->GetJITTimeInfo()->GetObjTypeSpecFldInfo(i);
+        ObjTypeSpecFldInfo * info = GetWorkItem()->GetJITTimeInfo()->GetObjTypeSpecFldInfo(i);
         if (info != nullptr)
         {
             Assert(info->GetObjTypeSpecFldId() < GetTopFunc()->GetWorkItem()->GetJITTimeInfo()->GetGlobalObjTypeSpecFldInfoCount());
@@ -1335,7 +1335,7 @@ Func::GetPolyCacheUtil(const uint index) const
     return this->m_polymorphicInlineCacheInfo->GetUtil(index);
 }
 
-JITObjTypeSpecFldInfo*
+ObjTypeSpecFldInfo*
 Func::GetObjTypeSpecFldInfo(const uint index) const
 {
     if (GetJITFunctionBody()->GetInlineCacheCount() == 0)
@@ -1347,7 +1347,7 @@ Func::GetObjTypeSpecFldInfo(const uint index) const
     return GetWorkItem()->GetJITTimeInfo()->GetObjTypeSpecFldInfo(index);
 }
 
-JITObjTypeSpecFldInfo*
+ObjTypeSpecFldInfo*
 Func::GetGlobalObjTypeSpecFldInfo(uint propertyInfoId) const
 {
     Assert(propertyInfoId < GetTopFunc()->GetWorkItem()->GetJITTimeInfo()->GetGlobalObjTypeSpecFldInfoCount());

+ 3 - 3
lib/Backend/Func.h

@@ -544,8 +544,8 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
 
     Js::Var AllocateNumber(double value);
 
-    JITObjTypeSpecFldInfo* GetObjTypeSpecFldInfo(const uint index) const;
-    JITObjTypeSpecFldInfo* GetGlobalObjTypeSpecFldInfo(uint propertyInfoId) const;
+    ObjTypeSpecFldInfo* GetObjTypeSpecFldInfo(const uint index) const;
+    ObjTypeSpecFldInfo* GetGlobalObjTypeSpecFldInfo(uint propertyInfoId) const;
 
     // Gets an inline cache pointer to use in jitted code. Cached data may not be stable while jitting. Does not return null.
     intptr_t GetRuntimeInlineCache(const uint index) const;
@@ -998,7 +998,7 @@ private:
     void * const    m_codeGenAllocators;
     YieldOffsetResumeLabelList * m_yieldOffsetResumeLabelList;
     StackArgWithFormalsTracker * stackArgWithFormalsTracker;
-    JITObjTypeSpecFldInfo ** m_globalObjTypeSpecFldInfoArray;
+    ObjTypeSpecFldInfo ** m_globalObjTypeSpecFldInfoArray;
     StackSym *CreateInlineeStackSym();
     IR::SymOpnd *GetInlineeOpndAtOffset(int32 offset);
     bool HasLocalVarSlotCreated() const { return m_localVarSlotsOffset != Js::Constants::InvalidOffset; }

+ 2 - 2
lib/Runtime/Language/FunctionCodeGenJitTimeData.cpp → lib/Backend/FunctionCodeGenJitTimeData.cpp

@@ -2,8 +2,8 @@
 // Copyright (C) Microsoft. All rights reserved.
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
-#include "RuntimeLanguagePch.h"
-#include "JITTimeFunctionBody.h"
+
+#include "Backend.h"
 
 #if ENABLE_NATIVE_CODEGEN
 namespace Js

+ 0 - 0
lib/Runtime/Language/FunctionCodeGenJitTimeData.h → lib/Backend/FunctionCodeGenJitTimeData.h


+ 8 - 18
lib/Backend/FunctionJITTimeInfo.cpp

@@ -109,12 +109,11 @@ FunctionJITTimeInfo::BuildJITTimeData(
             jitData->ldFldInlineeCount = jitData->bodyData->inlineCacheCount;
             jitData->ldFldInlinees = AnewArrayZ(alloc, FunctionJITTimeDataIDL*, jitData->bodyData->inlineCacheCount);
 
-            Field(Js::ObjTypeSpecFldInfo*)* objTypeSpecInfo = codeGenData->GetObjTypeSpecFldInfoArray()->GetInfoArray();
+            Field(ObjTypeSpecFldInfo*)* objTypeSpecInfo = codeGenData->GetObjTypeSpecFldInfoArray()->GetInfoArray();
             if(objTypeSpecInfo)
             {
                 jitData->objTypeSpecFldInfoCount = jitData->bodyData->inlineCacheCount;
-                jitData->objTypeSpecFldInfoArray = AnewArrayZ(alloc, ObjTypeSpecFldIDL, jitData->bodyData->inlineCacheCount);
-                JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(alloc, objTypeSpecInfo, jitData->objTypeSpecFldInfoCount, jitData->objTypeSpecFldInfoArray);
+                jitData->objTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)objTypeSpecInfo;
             }
             for (Js::InlineCacheIndex i = 0; i < jitData->bodyData->inlineCacheCount; ++i)
             {
@@ -129,12 +128,11 @@ FunctionJITTimeInfo::BuildJITTimeData(
         }
         if (!isInlinee && codeGenData->GetGlobalObjTypeSpecFldInfoCount() > 0)
         {
-            Field(Js::ObjTypeSpecFldInfo*)* globObjTypeSpecInfo = codeGenData->GetGlobalObjTypeSpecFldInfoArray();
+            Field(ObjTypeSpecFldInfo*)* globObjTypeSpecInfo = codeGenData->GetGlobalObjTypeSpecFldInfoArray();
             Assert(globObjTypeSpecInfo != nullptr);
 
             jitData->globalObjTypeSpecFldInfoCount = codeGenData->GetGlobalObjTypeSpecFldInfoCount();
-            jitData->globalObjTypeSpecFldInfoArray = AnewArrayZ(alloc, ObjTypeSpecFldIDL, jitData->globalObjTypeSpecFldInfoCount);
-            JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(alloc, globObjTypeSpecInfo, jitData->globalObjTypeSpecFldInfoCount, jitData->globalObjTypeSpecFldInfoArray);
+            jitData->globalObjTypeSpecFldInfoArray = (ObjTypeSpecFldIDL**)globObjTypeSpecInfo;
         }
         const Js::FunctionCodeGenJitTimeData * nextJITData = codeGenData->GetNext();
         if (nextJITData != nullptr)
@@ -255,7 +253,7 @@ FunctionJITTimeInfo::GetRuntimeInfo() const
     return reinterpret_cast<const FunctionJITRuntimeInfo*>(m_data.profiledRuntimeData);
 }
 
-JITObjTypeSpecFldInfo *
+ObjTypeSpecFldInfo *
 FunctionJITTimeInfo::GetObjTypeSpecFldInfo(uint index) const
 {
     Assert(index < GetBody()->GetInlineCacheCount());
@@ -263,24 +261,16 @@ FunctionJITTimeInfo::GetObjTypeSpecFldInfo(uint index) const
     {
         return nullptr;
     }
-    if (!m_data.objTypeSpecFldInfoArray[index].inUse)
-    {
-        return nullptr;
-    }
 
-    return reinterpret_cast<JITObjTypeSpecFldInfo *>(&m_data.objTypeSpecFldInfoArray[index]);
+    return reinterpret_cast<ObjTypeSpecFldInfo *>(m_data.objTypeSpecFldInfoArray[index]);
 }
 
-JITObjTypeSpecFldInfo *
+ObjTypeSpecFldInfo *
 FunctionJITTimeInfo::GetGlobalObjTypeSpecFldInfo(uint index) const
 {
     Assert(index < m_data.globalObjTypeSpecFldInfoCount);
-    if (!m_data.globalObjTypeSpecFldInfoArray[index].inUse)
-    {
-        return nullptr;
-    }
 
-    return reinterpret_cast<JITObjTypeSpecFldInfo *>(&m_data.globalObjTypeSpecFldInfoArray[index]);
+    return reinterpret_cast<ObjTypeSpecFldInfo *>(m_data.globalObjTypeSpecFldInfoArray[index]);
 }
 
 uint

+ 2 - 2
lib/Backend/FunctionJITTimeInfo.h

@@ -35,8 +35,8 @@ public:
     const FunctionJITRuntimeInfo * GetRuntimeInfo() const;
     const BVFixed * GetInlineesBV() const;
     const FunctionJITTimeInfo * GetJitTimeDataFromFunctionInfoAddr(intptr_t polyFuncInfo) const;
-    JITObjTypeSpecFldInfo * GetObjTypeSpecFldInfo(uint index) const;
-    JITObjTypeSpecFldInfo * GetGlobalObjTypeSpecFldInfo(uint index) const;
+    ObjTypeSpecFldInfo * GetObjTypeSpecFldInfo(uint index) const;
+    ObjTypeSpecFldInfo * GetGlobalObjTypeSpecFldInfo(uint index) const;
     uint GetGlobalObjTypeSpecFldInfoCount() const;
     const FunctionJITRuntimeInfo * GetInlineeForTargetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId, intptr_t inlineeFuncBodyAddr) const;
     const FunctionJITRuntimeInfo *GetInlineeRuntimeData(const Js::ProfileId profiledCallSiteId) const;

+ 1 - 1
lib/Backend/GlobOpt.cpp

@@ -4188,7 +4188,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
                 {
                     Assert(builtinOpnd->AsAddrOpnd()->m_isFunction);
 
-                    Js::BuiltinFunction builtinFunction = Js::JavascriptLibrary::GetBuiltInForFuncInfo(((JITTimeFixedField*)builtinOpnd->AsAddrOpnd()->m_metadata)->GetFuncInfoAddr(), func->GetThreadContextInfo());
+                    Js::BuiltinFunction builtinFunction = Js::JavascriptLibrary::GetBuiltInForFuncInfo(((FixedFieldInfo*)builtinOpnd->AsAddrOpnd()->m_metadata)->GetFuncInfoAddr(), func->GetThreadContextInfo());
                     if (builtinFunction == Js::BuiltinFunction::JavascriptFunction_Apply)
                     {
                         ClearArgumentsSym(src1->AsRegOpnd());

+ 1 - 1
lib/Backend/GlobOpt.h

@@ -514,7 +514,7 @@ public:
 
 struct ObjectTypePropertyEntry
 {
-    JITObjTypeSpecFldInfo* fldInfo;
+    ObjTypeSpecFldInfo* fldInfo;
     uint blockNumber;
 };
 

+ 1 - 1
lib/Backend/GlobOptFields.cpp

@@ -2117,7 +2117,7 @@ GlobOpt::PreparePropertySymOpndForTypeCheckSeq(IR::PropertySymOpnd * propertySym
         return false;
     }
 
-    JITObjTypeSpecFldInfo* info = propertySymOpnd->GetObjTypeSpecInfo();
+    ObjTypeSpecFldInfo* info = propertySymOpnd->GetObjTypeSpecInfo();
 
     if (info->UsesAccessor() || info->IsRootObjectNonConfigurableFieldLoad())
     {

+ 2 - 2
lib/Backend/IR.cpp

@@ -3379,10 +3379,10 @@ bool Instr::AreAllOpndInt64() const
     return isDstInt64 && isSrc1Int64 && isSrc2Int64;
 }
 
-JITTimeFixedField* Instr::GetFixedFunction() const
+FixedFieldInfo* Instr::GetFixedFunction() const
 {
     Assert(HasFixedFunctionAddressTarget());
-    JITTimeFixedField* function = (JITTimeFixedField*)this->m_src1->AsAddrOpnd()->m_metadata;
+    FixedFieldInfo* function = (FixedFieldInfo*)this->m_src1->AsAddrOpnd()->m_metadata;
     return function;
 }
 

+ 1 - 1
lib/Backend/IR.h

@@ -429,7 +429,7 @@ public:
     bool       HasByteCodeArgOutCapture();
     void       GenerateArgOutSnapshot();
     IR::Instr* GetArgOutSnapshot();
-    JITTimeFixedField* GetFixedFunction() const;
+    FixedFieldInfo* GetFixedFunction() const;
     uint       GetArgOutCount(bool getInterpreterArgOutCount);
     IR::PropertySymOpnd *GetPropertySymOpnd() const;
     bool       CallsAccessor(IR::PropertySymOpnd* methodOpnd = nullptr);

+ 8 - 8
lib/Backend/Inline.cpp

@@ -566,7 +566,7 @@ void Inline::FillInlineesDataArrayUsingFixedMethods(
     const FunctionJITTimeInfo* inlineeJitTimeData,
         __inout_ecount(inlineesDataArrayLength) const FunctionJITTimeInfo ** inlineesDataArray,
         uint inlineesDataArrayLength,
-        __inout_ecount(cachedFixedInlineeCount) JITTimeFixedField* fixedFieldInfoArray,
+        __inout_ecount(cachedFixedInlineeCount) FixedFieldInfo* fixedFieldInfoArray,
         uint16 cachedFixedInlineeCount
         )
 {
@@ -730,7 +730,7 @@ Inline::InlinePolymorphicFunctionUsingFixedMethods(IR::Instr *callInstr, const F
         return InlinePolymorphicFunction(callInstr, inlinerData, symCallerThis, profileId, pIsInlined, recursiveInlineDepth, true);
     }
 
-    JITTimeFixedField* fixedFunctionInfoArray = methodPropertyOpnd->GetFixedFieldInfoArray();
+    FixedFieldInfo* fixedFunctionInfoArray = methodPropertyOpnd->GetFixedFieldInfoArray();
 
     // It might so be the case that two objects of different types call the same function (body), for e.g., if they share the prototype on which the function is defined.
     uint uniqueFixedFunctionCount = HandleDifferentTypesSameFunction(fixedFunctionInfoArray, cachedFixedInlineeCount);
@@ -1162,7 +1162,7 @@ void Inline::InsertOneInlinee(IR::Instr* callInstr, IR::RegOpnd* returnValueOpnd
 }
 
 uint
-Inline::HandleDifferentTypesSameFunction(__inout_ecount(cachedFixedInlineeCount) JITTimeFixedField* fixedFunctionInfoArray, uint16 cachedFixedInlineeCount)
+Inline::HandleDifferentTypesSameFunction(__inout_ecount(cachedFixedInlineeCount) FixedFieldInfo* fixedFunctionInfoArray, uint16 cachedFixedInlineeCount)
 {
     uint16 uniqueCount = cachedFixedInlineeCount;
     uint16 swapIndex;
@@ -1173,7 +1173,7 @@ Inline::HandleDifferentTypesSameFunction(__inout_ecount(cachedFixedInlineeCount)
         {
             if (fixedFunctionInfoArray[i].GetFieldValue() == fixedFunctionInfoArray[j].GetFieldValue())
             {
-                JITTimeFixedField tmpInfo = fixedFunctionInfoArray[j];
+                FixedFieldInfo tmpInfo = fixedFunctionInfoArray[j];
                 fixedFunctionInfoArray[j] = fixedFunctionInfoArray[swapIndex];
                 fixedFunctionInfoArray[swapIndex] = tmpInfo;
                 fixedFunctionInfoArray[swapIndex - 1].SetNextHasSameFixedField();
@@ -1479,7 +1479,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
         return false;
     }
 
-    JITTimeFixedField * fixedField = nullptr;
+    FixedFieldInfo * fixedField = nullptr;
     if (!isPolymorphic)
     {
         fixedField = methodPropertyOpnd->HasFixedValue() ? methodPropertyOpnd->GetFixedFunction() : nullptr;
@@ -3993,7 +3993,7 @@ Inline::SplitConstructorCallCommon(
     // into a call to one of these helpers.
     if (skipNewScObj)
     {
-        JITTimeFixedField* ctor = newObjInstr->GetFixedFunction();
+        FixedFieldInfo* ctor = newObjInstr->GetFixedFunction();
         intptr_t ctorInfo = ctor->GetFuncInfoAddr();
         if ((ctorInfo == topFunc->GetThreadContextInfo()->GetJavascriptObjectNewInstanceAddr() ||
             ctorInfo == topFunc->GetThreadContextInfo()->GetJavascriptArrayNewInstanceAddr()) &&
@@ -4884,7 +4884,7 @@ Inline::MapFormals(Func *inlinee,
                 if (funcObjOpnd->IsAddrOpnd())
                 {
                     instr->m_opcode = Js::OpCode::Ld_A;
-                    instr->SetSrc1(IR::AddrOpnd::New(((JITTimeFixedField*)funcObjOpnd->AsAddrOpnd()->m_metadata)->GetEnvironmentAddr(),
+                    instr->SetSrc1(IR::AddrOpnd::New(((FixedFieldInfo*)funcObjOpnd->AsAddrOpnd()->m_metadata)->GetEnvironmentAddr(),
                         IR::AddrOpndKindDynamicFrameDisplay, instr->m_func));
                 }
                 else
@@ -5344,7 +5344,7 @@ Inline::GetInlineeHasArgumentObject(Func * inlinee)
                         {
                             Assert(builtInOpnd->AsAddrOpnd()->m_isFunction);
 
-                            Js::BuiltinFunction builtinFunction = Js::JavascriptLibrary::GetBuiltInForFuncInfo(((JITTimeFixedField*)builtInOpnd->AsAddrOpnd()->m_metadata)->GetFuncInfoAddr(), this->topFunc->GetThreadContextInfo());
+                            Js::BuiltinFunction builtinFunction = Js::JavascriptLibrary::GetBuiltInForFuncInfo(((FixedFieldInfo*)builtInOpnd->AsAddrOpnd()->m_metadata)->GetFuncInfoAddr(), this->topFunc->GetThreadContextInfo());
                             if (builtinFunction == Js::BuiltinFunction::JavascriptFunction_Apply)
                             {
                                 this->SetIsInInlinedApplyCall(true);

+ 2 - 2
lib/Backend/Inline.h

@@ -111,7 +111,7 @@ private:
         const FunctionJITTimeInfo* inlineeJitTimeData,
         __inout_ecount(inlineesDataArrayLength) const FunctionJITTimeInfo **inlineesDataArray,
         uint inlineesDataArrayLength,
-        __inout_ecount(cachedFixedInlineeCount) JITTimeFixedField* fixedFunctionInfoArray,
+        __inout_ecount(cachedFixedInlineeCount) FixedFieldInfo* fixedFunctionInfoArray,
         uint16 cachedFixedInlineeCount
         );
 
@@ -122,7 +122,7 @@ private:
     void InsertOneInlinee(IR::Instr* callInstr, IR::RegOpnd* returnValueOpnd,
         IR::Opnd* methodOpnd, const FunctionJITTimeInfo * inlineeJITData, const FunctionJITRuntimeInfo * inlineeRuntimeData, IR::LabelInstr* doneLabel, const StackSym* symCallerThis, bool fixedFunctionSafeThis, uint recursiveInlineDepth);
     void CompletePolymorphicInlining(IR::Instr* callInstr, IR::RegOpnd* returnValueOpnd, IR::LabelInstr* doneLabel, IR::Instr* dispatchStartLabel, IR::Instr* ldMethodFldInstr, IR::BailOutKind bailoutKind);
-    uint HandleDifferentTypesSameFunction(__inout_ecount(cachedFixedInlineeCount) JITTimeFixedField* fixedFunctionInfoArray, uint16 cachedFixedInlineeCount);
+    uint HandleDifferentTypesSameFunction(__inout_ecount(cachedFixedInlineeCount) FixedFieldInfo* fixedFunctionInfoArray, uint16 cachedFixedInlineeCount);
     void SetInlineeFrameStartSym(Func *inlinee, uint actualCount);
     void CloneCallSequence(IR::Instr* callInstr, IR::Instr* clonedCallInstr);
 

+ 0 - 337
lib/Backend/JITObjTypeSpecFldInfo.cpp

@@ -1,337 +0,0 @@
-//-------------------------------------------------------------------------------------------------------
-// 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"
-
-JITObjTypeSpecFldInfo::JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data) :
-    m_data(*data)
-{
-    CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(JITObjTypeSpecFldInfo));
-}
-
-bool
-JITObjTypeSpecFldInfo::UsesAuxSlot() const
-{
-    return GetFlags().usesAuxSlot;
-}
-
-bool
-JITObjTypeSpecFldInfo::UsesAccessor() const
-{
-    return GetFlags().usesAccessor;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
-{
-    return GetFlags().isRootObjectNonConfigurableFieldLoad;
-}
-
-bool
-JITObjTypeSpecFldInfo::HasEquivalentTypeSet() const
-{
-    return m_data.typeSet != nullptr;
-}
-
-bool
-JITObjTypeSpecFldInfo::DoesntHaveEquivalence() const
-{
-    return GetFlags().doesntHaveEquivalence;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsPoly() const
-{
-    return GetFlags().isPolymorphic;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsMono() const
-{
-    return !IsPoly();
-}
-
-bool
-JITObjTypeSpecFldInfo::IsBuiltIn() const
-{
-    return GetFlags().isBuiltIn;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsLoadedFromProto() const
-{
-    return GetFlags().isLoadedFromProto;
-}
-
-bool
-JITObjTypeSpecFldInfo::HasFixedValue() const
-{
-    return GetFlags().hasFixedValue;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsBeingStored() const
-{
-    return GetFlags().isBeingStored;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsBeingAdded() const
-{
-    return GetFlags().isBeingAdded;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
-{
-    return GetFlags().isRootObjectNonConfigurableField;
-}
-
-bool
-JITObjTypeSpecFldInfo::HasInitialType() const
-{
-    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
-}
-
-bool
-JITObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
-{
-    return IsMono();
-}
-
-bool
-JITObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
-{
-    return IsPoly();
-}
-
-Js::TypeId
-JITObjTypeSpecFldInfo::GetTypeId() const
-{
-    Assert(m_data.typeId != Js::TypeIds_Limit);
-    return (Js::TypeId)m_data.typeId;
-}
-
-Js::TypeId
-JITObjTypeSpecFldInfo::GetTypeId(uint i) const
-{
-    Assert(IsPoly());
-    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type->typeId;
-}
-
-Js::PropertyId
-JITObjTypeSpecFldInfo::GetPropertyId() const
-{
-    return (Js::PropertyId)m_data.propertyId;
-}
-
-uint16
-JITObjTypeSpecFldInfo::GetSlotIndex() const
-{
-    return m_data.slotIndex;
-}
-
-uint16
-JITObjTypeSpecFldInfo::GetFixedFieldCount() const
-{
-    return m_data.fixedFieldCount;
-}
-
-uint
-JITObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
-{
-    return m_data.id;
-}
-
-intptr_t
-JITObjTypeSpecFldInfo::GetProtoObject() const
-{
-    return m_data.protoObjectAddr;
-}
-
-intptr_t
-JITObjTypeSpecFldInfo::GetFieldValue(uint i) const
-{
-    Assert(IsPoly());
-    return m_data.fixedFieldInfoArray[i].fieldValue;
-}
-
-intptr_t
-JITObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
-{
-    return m_data.propertyGuardValueAddr;
-}
-
-intptr_t
-JITObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
-{
-    Assert(HasFixedValue() && GetFixedFieldCount() == 1);
-
-    return m_data.fixedFieldInfoArray[0].fieldValue;
-}
-
-JITTimeConstructorCache *
-JITObjTypeSpecFldInfo::GetCtorCache() const
-{
-    return (JITTimeConstructorCache*)m_data.ctorCache;
-}
-
-Js::EquivalentTypeSet *
-JITObjTypeSpecFldInfo::GetEquivalentTypeSet() const
-{
-    return (Js::EquivalentTypeSet *)m_data.typeSet;
-}
-
-JITTypeHolder
-JITObjTypeSpecFldInfo::GetType() const
-{
-    Assert(IsMono());
-    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[0].type);
-}
-
-JITTypeHolder
-JITObjTypeSpecFldInfo::GetType(uint i) const
-{
-    Assert(IsPoly());
-    return JITTypeHolder((JITType *)m_data.fixedFieldInfoArray[i].type);
-}
-
-JITTypeHolder
-JITObjTypeSpecFldInfo::GetInitialType() const
-{
-    return JITTypeHolder((JITType *)m_data.initialType);
-}
-
-JITTypeHolder
-JITObjTypeSpecFldInfo::GetFirstEquivalentType() const
-{
-    Assert(HasEquivalentTypeSet());
-    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
-}
-
-void
-JITObjTypeSpecFldInfo::SetIsBeingStored(bool value)
-{
-    ((Js::ObjTypeSpecFldInfoFlags*)&m_data.flags)->isBeingStored = value;
-}
-
-JITTimeFixedField *
-JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
-{
-    Assert(HasFixedValue());
-    if (IsPoly() && DoesntHaveEquivalence())
-    {
-        return nullptr;
-    }
-
-    Assert(m_data.fixedFieldInfoArray);
-    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
-    {
-        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[0];
-    }
-    return nullptr;
-}
-
-JITTimeFixedField *
-JITObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
-{
-    Assert(HasFixedValue());
-    Assert(IsPoly());
-    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
-    {
-        return (JITTimeFixedField *)&m_data.fixedFieldInfoArray[i];
-    }
-    return nullptr;
-}
-
-JITTimeFixedField *
-JITObjTypeSpecFldInfo::GetFixedFieldInfoArray()
-{
-    return (JITTimeFixedField*)m_data.fixedFieldInfoArray;
-}
-
-/* static */
-void
-JITObjTypeSpecFldInfo::BuildObjTypeSpecFldInfoArray(
-    __in ArenaAllocator * alloc,
-    _In_reads_(arrayLength) Field(Js::ObjTypeSpecFldInfo*)* objTypeSpecInfo,
-    __in uint arrayLength,
-    _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData)
-{
-    for (uint i = 0; i < arrayLength; ++i)
-    {
-        if (objTypeSpecInfo[i] == nullptr)
-        {
-            continue;
-        }
-        jitData[i].inUse = TRUE;
-        if (objTypeSpecInfo[i]->IsLoadedFromProto())
-        {
-            jitData[i].protoObjectAddr = (intptr_t)objTypeSpecInfo[i]->GetProtoObject();
-        }
-        jitData[i].propertyGuardValueAddr = (intptr_t)objTypeSpecInfo[i]->GetPropertyGuard()->GetAddressOfValue();
-        jitData[i].propertyId = objTypeSpecInfo[i]->GetPropertyId();
-        jitData[i].typeId = objTypeSpecInfo[i]->GetTypeId();
-        jitData[i].id = objTypeSpecInfo[i]->GetObjTypeSpecFldId();
-        jitData[i].flags = objTypeSpecInfo[i]->GetFlags();
-        jitData[i].slotIndex = objTypeSpecInfo[i]->GetSlotIndex();
-        jitData[i].fixedFieldCount = objTypeSpecInfo[i]->GetFixedFieldCount();
-
-        if (objTypeSpecInfo[i]->HasInitialType())
-        {
-            jitData[i].initialType = AnewStructZ(alloc, TypeIDL);
-            JITType::BuildFromJsType(objTypeSpecInfo[i]->GetInitialType(), (JITType*)jitData[i].initialType);
-        }
-
-        if (objTypeSpecInfo[i]->GetCtorCache() != nullptr)
-        {
-            jitData[i].ctorCache = objTypeSpecInfo[i]->GetCtorCache()->GetData();
-        }
-
-        CompileAssert(sizeof(Js::EquivalentTypeSet) == sizeof(EquivalentTypeSetIDL));
-        Js::EquivalentTypeSet * equivTypeSet = objTypeSpecInfo[i]->GetEquivalentTypeSet();
-        if (equivTypeSet != nullptr)
-        {
-            jitData[i].typeSet = (EquivalentTypeSetIDL*)equivTypeSet;
-        }
-
-        jitData[i].fixedFieldInfoArraySize = jitData[i].fixedFieldCount;
-        if (jitData[i].fixedFieldInfoArraySize == 0)
-        {
-            jitData[i].fixedFieldInfoArraySize = 1;
-        }
-        jitData[i].fixedFieldInfoArray = AnewArrayZ(alloc, FixedFieldIDL, jitData[i].fixedFieldInfoArraySize);
-        Js::FixedFieldInfo * ffInfo = objTypeSpecInfo[i]->GetFixedFieldInfoArray();
-        for (uint16 j = 0; j < jitData[i].fixedFieldInfoArraySize; ++j)
-        {
-            jitData[i].fixedFieldInfoArray[j].fieldValue = (intptr_t)PointerValue(ffInfo[j].fieldValue);
-            jitData[i].fixedFieldInfoArray[j].nextHasSameFixedField = ffInfo[j].nextHasSameFixedField;
-            if (ffInfo[j].fieldValue != nullptr && Js::JavascriptFunction::Is(ffInfo[j].fieldValue))
-            {
-                Js::JavascriptFunction * funcObj = Js::JavascriptFunction::FromVar(ffInfo[j].fieldValue);
-                jitData[i].fixedFieldInfoArray[j].valueType = ValueType::FromObject(funcObj).GetRawData();
-                jitData[i].fixedFieldInfoArray[j].funcInfoAddr = (intptr_t)funcObj->GetFunctionInfo();
-                jitData[i].fixedFieldInfoArray[j].isClassCtor = funcObj->GetFunctionInfo()->IsClassConstructor();
-                jitData[i].fixedFieldInfoArray[j].localFuncId = (intptr_t)funcObj->GetFunctionInfo()->GetLocalFunctionId();
-                if (Js::ScriptFunction::Is(ffInfo[j].fieldValue))
-                {
-                    jitData[i].fixedFieldInfoArray[j].environmentAddr = (intptr_t)Js::ScriptFunction::FromVar(funcObj)->GetEnvironment();
-                }
-            }
-            if (ffInfo[j].type != nullptr)
-            {
-                jitData[i].fixedFieldInfoArray[j].type = AnewStructZ(alloc, TypeIDL);
-                // TODO: OOP JIT, maybe type should be out of line? might not save anything on x64 though
-                JITType::BuildFromJsType(ffInfo[j].type, (JITType*)jitData[i].fixedFieldInfoArray[j].type);
-            }
-        }
-    }
-}
-
-Js::ObjTypeSpecFldInfoFlags
-JITObjTypeSpecFldInfo::GetFlags() const
-{
-    return (Js::ObjTypeSpecFldInfoFlags)m_data.flags;
-}

+ 0 - 70
lib/Backend/JITObjTypeSpecFldInfo.h

@@ -1,70 +0,0 @@
-//-------------------------------------------------------------------------------------------------------
-// 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
-
-class JITObjTypeSpecFldInfo
-{
-public:
-    JITObjTypeSpecFldInfo(ObjTypeSpecFldIDL * data);
-    bool UsesAuxSlot() const;
-    bool UsesAccessor() const;
-    bool IsRootObjectNonConfigurableFieldLoad() const;
-    bool HasEquivalentTypeSet() const;
-    bool DoesntHaveEquivalence() const;
-    bool IsPoly() const;
-    bool IsMono() const;
-    bool IsBuiltIn() const;
-    bool IsLoadedFromProto() const;
-    bool HasFixedValue() const;
-    bool IsBeingStored() const;
-    bool IsBeingAdded() const;
-    bool IsRootObjectNonConfigurableField() const;
-    bool HasInitialType() const;
-    bool IsMonoObjTypeSpecCandidate() const;
-    bool IsPolyObjTypeSpecCandidate() const;
-
-    Js::TypeId GetTypeId() const;
-    Js::TypeId GetTypeId(uint i) const;
-
-    Js::PropertyId GetPropertyId() const;
-    uint16 GetSlotIndex() const;
-    uint16 GetFixedFieldCount() const;
-
-    uint GetObjTypeSpecFldId() const;
-
-    intptr_t GetProtoObject() const;
-    intptr_t GetFieldValue(uint i) const;
-    intptr_t GetPropertyGuardValueAddr() const;
-    intptr_t GetFieldValueAsFixedDataIfAvailable() const;
-
-    JITTimeConstructorCache * GetCtorCache() const;
-
-    Js::EquivalentTypeSet * GetEquivalentTypeSet() const;
-    JITTypeHolder GetType() const;
-    JITTypeHolder GetType(uint i) const;
-    JITTypeHolder GetInitialType() const;
-    JITTypeHolder GetFirstEquivalentType() const;
-
-    JITTimeFixedField * GetFixedFieldIfAvailableAsFixedFunction();
-    JITTimeFixedField * GetFixedFieldIfAvailableAsFixedFunction(uint i);
-    JITTimeFixedField * GetFixedFieldInfoArray();
-
-    void SetIsBeingStored(bool value); // REVIEW: this doesn't flow out of JIT, should it?
-
-    static void BuildObjTypeSpecFldInfoArray(
-        __in ArenaAllocator * alloc,
-        _In_reads_(arrayLength) Field(Js::ObjTypeSpecFldInfo*)* objTypeSpecInfo,
-        __in uint arrayLength,
-        _Inout_updates_(arrayLength) ObjTypeSpecFldIDL * jitData);
-
-    // TODO: OOP JIT, implement this
-    char16* GetCacheLayoutString() { __debugbreak(); return nullptr; }
-
-private:
-    Js::ObjTypeSpecFldInfoFlags GetFlags() const;
-
-    ObjTypeSpecFldIDL m_data;
-};

+ 0 - 63
lib/Backend/JITTimeFixedField.cpp

@@ -1,63 +0,0 @@
-//-------------------------------------------------------------------------------------------------------
-// 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"
-
-CompileAssert(sizeof(FixedFieldIDL) == sizeof(JITTimeFixedField));
-
-void
-JITTimeFixedField::SetNextHasSameFixedField()
-{
-    m_data.nextHasSameFixedField = TRUE;
-}
-
-bool
-JITTimeFixedField::IsClassCtor() const
-{
-    return m_data.isClassCtor != FALSE;
-}
-
-bool
-JITTimeFixedField::NextHasSameFixedField() const
-{
-    return m_data.nextHasSameFixedField != FALSE;
-}
-
-uint
-JITTimeFixedField::GetLocalFuncId() const
-{
-    return m_data.localFuncId;
-}
-
-ValueType
-JITTimeFixedField::GetValueType() const
-{
-    CompileAssert(sizeof(ValueType) == sizeof(uint16));
-    return *(ValueType*)&m_data.valueType;
-}
-
-intptr_t
-JITTimeFixedField::GetFieldValue() const
-{
-    return m_data.fieldValue;
-}
-
-intptr_t
-JITTimeFixedField::GetFuncInfoAddr() const
-{
-    return m_data.funcInfoAddr;
-}
-
-intptr_t
-JITTimeFixedField::GetEnvironmentAddr() const
-{
-    return m_data.environmentAddr;
-}
-
-JITType *
-JITTimeFixedField::GetType() const
-{
-    return (JITType*)m_data.type;
-}

+ 1 - 0
lib/Backend/JITType.cpp

@@ -20,6 +20,7 @@ void
 JITType::BuildFromJsType(__in Js::Type * jsType, __out JITType * jitType)
 {
     TypeIDL * data = jitType->GetData();
+    data->exists = true;
     data->addr = jsType;
     data->typeId = jsType->GetTypeId();
     data->libAddr = jsType->GetLibrary();

+ 4 - 4
lib/Backend/Lower.cpp

@@ -4813,7 +4813,7 @@ Lowerer::LowerNewScObject(IR::Instr *newObjInstr, bool callCtor, bool hasArgs, b
 
         // If we have no arguments (i.e. the argument chain is empty), we can recognize a couple of common special cases, such
         // as new Object() or new Array(), for which we have optimized helpers.
-        JITTimeFixedField* ctor = newObjInstr->GetFixedFunction();
+        FixedFieldInfo* ctor = newObjInstr->GetFixedFunction();
         intptr_t ctorInfo = ctor->GetFuncInfoAddr();
         if (!hasArgs && (ctorInfo == m_func->GetThreadContextInfo()->GetJavascriptObjectNewInstanceAddr() || ctorInfo == m_func->GetThreadContextInfo()->GetJavascriptArrayNewInstanceAddr()))
         {
@@ -5170,7 +5170,7 @@ bool Lowerer::TryLowerNewScObjectWithFixedCtorCache(IR::Instr* newObjInstr, IR::
 
     // If we are calling new on a class constructor, the contract is that we pass new.target as the 'this' argument.
     // function is the constructor on which we called new - which is new.target.
-    JITTimeFixedField* ctor = newObjInstr->GetFixedFunction();
+    FixedFieldInfo* ctor = newObjInstr->GetFixedFunction();
 
     if (ctor->IsClassCtor())
     {
@@ -7708,7 +7708,7 @@ Lowerer::CreateEquivalentTypeGuardAndLinkToGuardedProperties(JITTypeHolder type,
 
     FOREACH_BITSET_IN_SPARSEBV(propOpId, propOps)
     {
-        JITObjTypeSpecFldInfo* propOpInfo = this->m_func->GetGlobalObjTypeSpecFldInfo(propOpId);
+        ObjTypeSpecFldInfo* propOpInfo = this->m_func->GetGlobalObjTypeSpecFldInfo(propOpId);
         Js::PropertyId propertyId = propOpInfo->GetPropertyId();
         Js::PropertyIndex propOpIndex = Js::Constants::NoSlot;
         bool hasFixedValue = propOpInfo->HasFixedValue();
@@ -7824,7 +7824,7 @@ Lowerer::LinkGuardToGuardedProperties(const BVSparse<JitArenaAllocator>* guarded
     // For every entry in the bit vector, register the guard for the corresponding property ID.
     FOREACH_BITSET_IN_SPARSEBV(propertyOpId, guardedPropOps)
     {
-        JITObjTypeSpecFldInfo* propertyOpInfo = this->m_func->GetGlobalObjTypeSpecFldInfo(propertyOpId);
+        ObjTypeSpecFldInfo* propertyOpInfo = this->m_func->GetGlobalObjTypeSpecFldInfo(propertyOpId);
         Js::PropertyId propertyId = propertyOpInfo->GetPropertyId();
 
         // It's okay for an equivalent type check to be registered as a guard against a property becoming read-only. This transpires if, there is

+ 12 - 10
lib/Backend/NativeCodeGenerator.cpp

@@ -1162,6 +1162,8 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
         body->SetDisableInlineSpread(true);
     }
 
+    NativeCodeGenerator::LogCodeGenDone(workItem, &start_time);
+
 #ifdef PROFILE_BAILOUT_RECORD_MEMORY
     if (Js::Configuration::Global.flags.ProfileBailOutRecordMemory)
     {
@@ -2329,7 +2331,7 @@ NativeCodeGenerator::GatherCodeGenData(
                     inlineCache = functionBody->GetInlineCache(i);
                 }
 
-                Js::ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr;
+                ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr;
 
 #if ENABLE_DEBUG_CONFIG_OPTIONS
                 if (PHASE_VERBOSE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_VERBOSE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
@@ -2361,7 +2363,7 @@ NativeCodeGenerator::GatherCodeGenData(
                         if (!(functionBody->IsInDebugMode() && inlineCache->GetType() &&
                               inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject))
                         {
-                            objTypeSpecFldInfo = Js::ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
+                            objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
                             if (objTypeSpecFldInfo)
                             {
                                 IncInlineCacheCount(clonedMonoInlineCacheCount);
@@ -2391,7 +2393,7 @@ NativeCodeGenerator::GatherCodeGenData(
                 {
                     if (!objTypeSpecFldInfo && (cacheType & Js::FldInfo_FromAccessor) && (cacheType & Js::FldInfo_InlineCandidate))
                     {
-                        objTypeSpecFldInfo = Js::ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
+                        objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
                         if (objTypeSpecFldInfo)
                         {
                             inlineGetterSetter = true;
@@ -2432,7 +2434,7 @@ NativeCodeGenerator::GatherCodeGenData(
                                 // non configurable
                                 if (objTypeSpecFldInfo == nullptr)
                                 {
-                                    objTypeSpecFldInfo = Js::ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
+                                    objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
                                     if (objTypeSpecFldInfo)
                                     {
                                         IncInlineCacheCount(clonedMonoInlineCacheCount);
@@ -2453,7 +2455,7 @@ NativeCodeGenerator::GatherCodeGenData(
             else if(function && Js::ScriptFunctionWithInlineCache::Is(function) && (cacheType & Js::FldInfo_InlineCandidate || !polymorphicCacheOnFunctionBody))
             {
                 Js::InlineCache *inlineCache = Js::ScriptFunctionWithInlineCache::FromVar(function)->GetInlineCache(i);
-                Js::ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr;
+                ObjTypeSpecFldInfo* objTypeSpecFldInfo = nullptr;
 
                 if(!PHASE_OFF(Js::ObjTypeSpecPhase, functionBody) || !PHASE_OFF(Js::FixedMethodsPhase, functionBody))
                 {
@@ -2466,7 +2468,7 @@ NativeCodeGenerator::GatherCodeGenData(
                         if (!(functionBody->IsInDebugMode() && inlineCache->GetType() &&
                               inlineCache->GetType()->GetTypeId() == Js::TypeIds_ActivationObject))
                         {
-                            objTypeSpecFldInfo = Js::ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
+                            objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), inlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
                             if (objTypeSpecFldInfo)
                             {
                                 IncInlineCacheCount(clonedMonoInlineCacheCount);
@@ -2518,7 +2520,7 @@ NativeCodeGenerator::GatherCodeGenData(
                                 Output::Flush();
                             }
 #endif
-                            Js::ObjTypeSpecFldInfo* objTypeSpecFldInfo = Js::ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), polymorphicInlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
+                            ObjTypeSpecFldInfo* objTypeSpecFldInfo = ObjTypeSpecFldInfo::CreateFrom(objTypeSpecFldInfoList->Count(), polymorphicInlineCache, i, entryPoint, topFunctionBody, functionBody, InlineCacheStatsArg(jitTimeData));
                             if (objTypeSpecFldInfo != nullptr)
                             {
                                 if (!isJitTimeDataComputed)
@@ -2824,7 +2826,7 @@ NativeCodeGenerator::GatherCodeGenData(
             //    then even if the field info flags say that the field access may be polymorphic, carry that optimism forward and try to inline apply target.
             if (getSetInlineCandidate ^ callApplyInlineCandidate)
             {
-                Js::ObjTypeSpecFldInfo* info = jitTimeData->GetObjTypeSpecFldInfoArray()->GetInfo(functionBody, inlineCacheIndex);
+                ObjTypeSpecFldInfo* info = jitTimeData->GetObjTypeSpecFldInfoArray()->GetInfo(functionBody, inlineCacheIndex);
                 if (info == nullptr)
                 {
                     continue;
@@ -3003,9 +3005,9 @@ NativeCodeGenerator::GatherCodeGenData(Js::FunctionBody *const topFunctionBody,
 #endif
 
         uint objTypeSpecFldInfoCount = objTypeSpecFldInfoList->Count();
-        jitTimeData->SetGlobalObjTypeSpecFldInfoArray(RecyclerNewArray(recycler, Field(Js::ObjTypeSpecFldInfo*), objTypeSpecFldInfoCount), objTypeSpecFldInfoCount);
+        jitTimeData->SetGlobalObjTypeSpecFldInfoArray(RecyclerNewArray(recycler, Field(ObjTypeSpecFldInfo*), objTypeSpecFldInfoCount), objTypeSpecFldInfoCount);
         uint propertyInfoId = objTypeSpecFldInfoCount - 1;
-        FOREACH_SLISTCOUNTED_ENTRY(Js::ObjTypeSpecFldInfo*, info, objTypeSpecFldInfoList)
+        FOREACH_SLISTCOUNTED_ENTRY(ObjTypeSpecFldInfo*, info, objTypeSpecFldInfoList)
         {
             // Clear field values we don't need so we don't unnecessarily pin them while JIT-ing.
             if (!info->GetKeepFieldValue() && !(info->IsPoly() && info->DoesntHaveEquivalence()))

+ 2 - 2
lib/Backend/NativeCodeGenerator.h

@@ -8,9 +8,9 @@ struct CodeGenWorkItem;
 struct JsFunctionCodeGen;
 struct JsLoopBodyCodeGen;
 class InliningDecider;
+class ObjTypeSpecFldInfo;
 namespace Js
 {
-    class ObjTypeSpecFldInfo;
     class FunctionCodeGenJitTimeData;
     class RemoteScriptContext;
 };
@@ -81,7 +81,7 @@ private:
     void UpdateJITState();
     static void LogCodeGenStart(CodeGenWorkItem * workItem, LARGE_INTEGER * start_time);
     static void LogCodeGenDone(CodeGenWorkItem * workItem, LARGE_INTEGER * start_time);
-    typedef SListCounted<Js::ObjTypeSpecFldInfo*, ArenaAllocator> ObjTypeSpecFldInfoList;
+    typedef SListCounted<ObjTypeSpecFldInfo*, ArenaAllocator> ObjTypeSpecFldInfoList;
 
     template<bool IsInlinee> void GatherCodeGenData(
         Recycler *const recycler,

+ 1007 - 0
lib/Backend/ObjTypeSpecFldInfo.cpp

@@ -0,0 +1,1007 @@
+//-------------------------------------------------------------------------------------------------------
+// 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"
+
+CompileAssert(sizeof(ObjTypeSpecFldIDL) == sizeof(ObjTypeSpecFldInfo));
+
+bool
+ObjTypeSpecFldInfo::UsesAuxSlot() const
+{
+    return GetFlags().usesAuxSlot;
+}
+
+bool
+ObjTypeSpecFldInfo::UsesAccessor() const
+{
+    return GetFlags().usesAccessor;
+}
+
+bool
+ObjTypeSpecFldInfo::IsRootObjectNonConfigurableFieldLoad() const
+{
+    return GetFlags().isRootObjectNonConfigurableFieldLoad;
+}
+
+bool
+ObjTypeSpecFldInfo::HasEquivalentTypeSet() const
+{
+    return m_data.typeSet != nullptr;
+}
+
+bool
+ObjTypeSpecFldInfo::DoesntHaveEquivalence() const
+{
+    return GetFlags().doesntHaveEquivalence;
+}
+
+bool
+ObjTypeSpecFldInfo::IsPoly() const
+{
+    return GetFlags().isPolymorphic;
+}
+
+bool
+ObjTypeSpecFldInfo::IsMono() const
+{
+    return !IsPoly();
+}
+
+bool
+ObjTypeSpecFldInfo::IsBuiltIn() const
+{
+    return GetFlags().isBuiltIn;
+}
+
+bool
+ObjTypeSpecFldInfo::IsLoadedFromProto() const
+{
+    return GetFlags().isLoadedFromProto;
+}
+
+bool
+ObjTypeSpecFldInfo::HasFixedValue() const
+{
+    return GetFlags().hasFixedValue;
+}
+
+bool
+ObjTypeSpecFldInfo::IsBeingStored() const
+{
+    return GetFlags().isBeingStored;
+}
+
+bool
+ObjTypeSpecFldInfo::IsBeingAdded() const
+{
+    return GetFlags().isBeingAdded;
+}
+
+bool
+ObjTypeSpecFldInfo::IsRootObjectNonConfigurableField() const
+{
+    return GetFlags().isRootObjectNonConfigurableField;
+}
+
+bool
+ObjTypeSpecFldInfo::HasInitialType() const
+{
+    return IsMono() && !IsLoadedFromProto() && m_data.initialType != nullptr;
+}
+
+bool
+ObjTypeSpecFldInfo::IsMonoObjTypeSpecCandidate() const
+{
+    return IsMono();
+}
+
+bool
+ObjTypeSpecFldInfo::IsPolyObjTypeSpecCandidate() const
+{
+    return IsPoly();
+}
+
+Js::TypeId
+ObjTypeSpecFldInfo::GetTypeId() const
+{
+    Assert(m_data.typeId != Js::TypeIds_Limit);
+    return (Js::TypeId)m_data.typeId;
+}
+
+Js::TypeId
+ObjTypeSpecFldInfo::GetTypeId(uint i) const
+{
+    Assert(IsPoly());
+    return (Js::TypeId)m_data.fixedFieldInfoArray[i].type.typeId;
+}
+
+Js::PropertyId
+ObjTypeSpecFldInfo::GetPropertyId() const
+{
+    return (Js::PropertyId)m_data.propertyId;
+}
+
+uint16
+ObjTypeSpecFldInfo::GetSlotIndex() const
+{
+    return m_data.slotIndex;
+}
+
+uint16
+ObjTypeSpecFldInfo::GetFixedFieldCount() const
+{
+    return m_data.fixedFieldCount;
+}
+
+uint
+ObjTypeSpecFldInfo::GetObjTypeSpecFldId() const
+{
+    return m_data.id;
+}
+
+intptr_t
+ObjTypeSpecFldInfo::GetProtoObject() const
+{
+    return m_data.protoObjectAddr;
+}
+
+intptr_t
+ObjTypeSpecFldInfo::GetFieldValue(uint i) const
+{
+    Assert(IsPoly());
+    return m_data.fixedFieldInfoArray[i].fieldValue;
+}
+
+intptr_t
+ObjTypeSpecFldInfo::GetPropertyGuardValueAddr() const
+{
+    return m_data.propertyGuardValueAddr;
+}
+
+intptr_t
+ObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
+{
+    Assert(HasFixedValue() && GetFixedFieldCount() == 1);
+
+    return m_data.fixedFieldInfoArray[0].fieldValue;
+}
+
+JITTimeConstructorCache *
+ObjTypeSpecFldInfo::GetCtorCache() const
+{
+    return (JITTimeConstructorCache*)m_data.ctorCache;
+}
+
+Js::EquivalentTypeSet *
+ObjTypeSpecFldInfo::GetEquivalentTypeSet() const
+{
+    return (Js::EquivalentTypeSet *)m_data.typeSet;
+}
+
+JITTypeHolder
+ObjTypeSpecFldInfo::GetType() const
+{
+    Assert(IsMono());
+    if (!m_data.fixedFieldInfoArray[0].type.exists)
+    {
+        return nullptr;
+    }
+    return JITTypeHolder((JITType *)&m_data.fixedFieldInfoArray[0].type);
+}
+
+JITTypeHolder
+ObjTypeSpecFldInfo::GetType(uint i) const
+{
+    Assert(IsPoly());
+    if (!m_data.fixedFieldInfoArray[i].type.exists)
+    {
+        return nullptr;
+    }
+    return JITTypeHolder((JITType *)&m_data.fixedFieldInfoArray[i].type);
+}
+
+JITTypeHolder
+ObjTypeSpecFldInfo::GetInitialType() const
+{
+    return JITTypeHolder((JITType *)m_data.initialType);
+}
+
+JITTypeHolder
+ObjTypeSpecFldInfo::GetFirstEquivalentType() const
+{
+    Assert(HasEquivalentTypeSet());
+    return JITTypeHolder(GetEquivalentTypeSet()->GetFirstType());
+}
+
+void
+ObjTypeSpecFldInfo::SetIsBeingStored(bool value)
+{
+    GetFlagsPtr()->isBeingStored = value;
+}
+
+FixedFieldInfo *
+ObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction()
+{
+    Assert(HasFixedValue());
+    Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
+    Assert(m_data.fixedFieldInfoArray);
+    if (m_data.fixedFieldInfoArray[0].funcInfoAddr != 0)
+    {
+        return (FixedFieldInfo *)&m_data.fixedFieldInfoArray[0];
+    }
+    return nullptr;
+}
+
+FixedFieldInfo *
+ObjTypeSpecFldInfo::GetFixedFieldIfAvailableAsFixedFunction(uint i)
+{
+    Assert(HasFixedValue());
+    Assert(IsPoly());
+    if (m_data.fixedFieldCount > 0 && m_data.fixedFieldInfoArray[i].funcInfoAddr != 0)
+    {
+        return (FixedFieldInfo *)&m_data.fixedFieldInfoArray[i];
+    }
+    return nullptr;
+}
+
+FixedFieldInfo *
+ObjTypeSpecFldInfo::GetFixedFieldInfoArray()
+{
+    return (FixedFieldInfo*)m_data.fixedFieldInfoArray;
+}
+
+ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::InlineCache* cache, uint cacheId,
+    Js::EntryPointInfo *entryPoint, Js::FunctionBody* const topFunctionBody, Js::FunctionBody *const functionBody, Js::FieldAccessStatsPtr inlineCacheStats)
+{
+    if (cache->IsEmpty())
+    {
+        return nullptr;
+    }
+
+    Js::InlineCache localCache(*cache);
+
+    // Need to keep a reference to the types before memory allocation in case they are tagged
+    Js::Type * type = nullptr;
+    Js::Type * typeWithoutProperty = nullptr;
+    Js::Type * propertyOwnerType;
+    bool isLocal = localCache.IsLocal();
+    bool isProto = localCache.IsProto();
+    bool isAccessor = localCache.IsAccessor();
+    bool isGetter = localCache.IsGetterAccessor();
+    if (isLocal)
+    {
+        type = TypeWithoutAuxSlotTag(localCache.u.local.type);
+        if (localCache.u.local.typeWithoutProperty)
+        {
+            typeWithoutProperty = TypeWithoutAuxSlotTag(localCache.u.local.typeWithoutProperty);
+        }
+        propertyOwnerType = type;
+    }
+    else if (isProto)
+    {
+        type = TypeWithoutAuxSlotTag(localCache.u.proto.type);
+        propertyOwnerType = localCache.u.proto.prototypeObject->GetType();
+    }
+    else
+    {
+        if (PHASE_OFF(Js::FixAccessorPropsPhase, functionBody))
+        {
+            return nullptr;
+        }
+
+        type = TypeWithoutAuxSlotTag(localCache.u.accessor.type);
+        propertyOwnerType = localCache.u.accessor.object->GetType();
+    }
+
+    Js::ScriptContext* scriptContext = functionBody->GetScriptContext();
+    Recycler *const recycler = scriptContext->GetRecycler();
+
+    Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(cacheId);
+    uint16 slotIndex = Js::Constants::NoSlot;
+    bool usesAuxSlot = false;
+    Js::DynamicObject* prototypeObject = nullptr;
+    Js::PropertyGuard* propertyGuard = nullptr;
+    JITTimeConstructorCache* ctorCache = nullptr;
+    Js::Var fieldValue = nullptr;
+    bool keepFieldValue = false;
+    bool isFieldValueFixed = false;
+    bool isMissing = false;
+    bool isBuiltIn = false;
+
+    // Save untagged type pointers, remembering whether the original type was tagged.
+    // The type pointers must be untagged so that the types cannot be collected during JIT.
+
+    if (isLocal)
+    {
+        slotIndex = localCache.u.local.slotIndex;
+        if (type != localCache.u.local.type)
+        {
+            usesAuxSlot = true;
+        }
+        if (typeWithoutProperty)
+        {
+            Assert(entryPoint->GetJitTransferData() != nullptr);
+            entryPoint->GetJitTransferData()->AddJitTimeTypeRef(typeWithoutProperty, recycler);
+
+            // 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);
+        }
+    }
+    else if (isProto)
+    {
+        prototypeObject = localCache.u.proto.prototypeObject;
+        slotIndex = localCache.u.proto.slotIndex;
+        if (type != localCache.u.proto.type)
+        {
+            usesAuxSlot = true;
+            fieldValue = prototypeObject->GetAuxSlot(slotIndex);
+        }
+        else
+        {
+            fieldValue = prototypeObject->GetInlineSlot(slotIndex);
+        }
+        isMissing = localCache.u.proto.isMissing;
+        propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+    }
+    else
+    {
+        slotIndex = localCache.u.accessor.slotIndex;
+        if (type != localCache.u.accessor.type)
+        {
+            usesAuxSlot = true;
+            fieldValue = localCache.u.accessor.object->GetAuxSlot(slotIndex);
+        }
+        else
+        {
+            fieldValue = localCache.u.accessor.object->GetInlineSlot(slotIndex);
+        }
+    }
+
+    // Keep the type alive until the entry point is installed. Note that this is longer than just during JIT, for which references
+    // from the JitTimeData would have been enough.
+    Assert(entryPoint->GetJitTransferData() != nullptr);
+    entryPoint->GetJitTransferData()->AddJitTimeTypeRef(type, recycler);
+
+    bool allFixedPhaseOFF = PHASE_OFF(Js::FixedMethodsPhase, topFunctionBody) & PHASE_OFF(Js::UseFixedDataPropsPhase, topFunctionBody);
+
+    if (!allFixedPhaseOFF)
+    {
+        Assert(propertyOwnerType != nullptr);
+        if (Js::DynamicType::Is(propertyOwnerType->GetTypeId()))
+        {
+            Js::DynamicTypeHandler* propertyOwnerTypeHandler = ((Js::DynamicType*)propertyOwnerType)->GetTypeHandler();
+            Js::PropertyRecord const * const fixedPropertyRecord = functionBody->GetScriptContext()->GetPropertyName(propertyId);
+            Js::Var fixedProperty = nullptr;
+            Js::JavascriptFunction* functionObject = nullptr;
+
+            if (isLocal || isProto)
+            {
+                if (typeWithoutProperty == nullptr)
+                {
+                    // Since we don't know if this cache is used for LdMethodFld, we may fix up (use as fixed) too
+                    // aggressively here, if we load a function that we don't actually call.  This happens in the case
+                    // of constructors (e.g. Object.defineProperty or Object.create).
+                    // TODO (InlineCacheCleanup): if we don't zero some slot(s) in the inline cache, we could store a bit there
+                    // indicating if this cache is used by LdMethodFld, and only ask then. We could even store a bit in the cache
+                    // indicating that the value loaded is a fixed function (or at least may still be). That last bit could work
+                    // even if we zero inline caches, since we would always set it when populating the cache.
+                    propertyOwnerTypeHandler->TryUseFixedProperty(fixedPropertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedMethodProperty | Js::FixedPropertyKind::FixedDataProperty), scriptContext);
+                }
+            }
+            else
+            {
+                propertyOwnerTypeHandler->TryUseFixedAccessor(fixedPropertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedAccessorProperty), isGetter, scriptContext);
+            }
+
+            if (fixedProperty != nullptr && propertyGuard == nullptr)
+            {
+                propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
+            }
+
+            if (fixedProperty != nullptr && Js::JavascriptFunction::Is(fixedProperty))
+            {
+                functionObject = (Js::JavascriptFunction *)fixedProperty;
+                if (PHASE_VERBOSE_TRACE(Js::FixedMethodsPhase, functionBody))
+                {
+                    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+                    char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+
+                    Js::DynamicObject* protoObject = isProto ? prototypeObject : nullptr;
+                    Output::Print(_u("FixedFields: function %s (%s) cloning cache with fixed method: %s (%s), function: 0x%p, body: 0x%p (cache id: %d, layout: %s, type: 0x%p, proto: 0x%p, proto type: 0x%p)\n"),
+                        functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer),
+                        fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionProxy() ?
+                        functionObject->GetFunctionInfo()->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
+                        cacheId, isProto ? _u("proto") : _u("local"), type, protoObject, protoObject != nullptr ? protoObject->GetType() : nullptr);
+                    Output::Flush();
+                }
+
+                if (PHASE_VERBOSE_TESTTRACE(Js::FixedMethodsPhase, functionBody))
+                {
+                    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+                    char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+
+                    Output::Print(_u("FixedFields: function %s (%s) cloning cache with fixed method: %s (%s) (cache id: %d, layout: %s)\n"),
+                        functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionProxy() ?
+                        functionObject->GetFunctionInfo()->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
+                        cacheId, isProto ? _u("proto") : _u("local"));
+                    Output::Flush();
+                }
+
+                // We don't need to check for a singleton here. We checked that the singleton still existed
+                // when we obtained the fixed field value inside TryUseFixedProperty. Since we don't need the
+                // singleton instance later in this function, we don't care if the instance got collected.
+                // We get the type handler from the propertyOwnerType, which we got from the cache. At runtime,
+                // if the object is collected, it is by definition unreachable and thus the code in the function
+                // we're about to emit cannot reach the object to try to access any of this object's properties.
+
+                Js::ConstructorCache* runtimeConstructorCache = functionObject->GetConstructorCache();
+                if (runtimeConstructorCache->IsSetUpForJit() && runtimeConstructorCache->GetScriptContext() == scriptContext)
+                {
+                    Js::FunctionInfo* functionInfo = functionObject->GetFunctionInfo();
+                    Assert(functionInfo != nullptr);
+                    Assert((functionInfo->GetAttributes() & Js::FunctionInfo::ErrorOnNew) == 0);
+
+                    Assert(!runtimeConstructorCache->IsDefault());
+
+                    if (runtimeConstructorCache->IsNormal())
+                    {
+                        Assert(runtimeConstructorCache->GetType()->GetIsShared());
+                        // If we populated the cache with initial type before calling the constructor, but then didn't end up updating the cache
+                        // after the constructor and shrinking (and locking) the inline slot capacity, we must lock it now.  In that case it is
+                        // also possible that the inline slot capacity was shrunk since we originally cached it, so we must update it also.
+#if DBG_DUMP
+                        if (!runtimeConstructorCache->GetType()->GetTypeHandler()->GetIsInlineSlotCapacityLocked())
+                        {
+                            if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
+                            {
+                                char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+                                char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+
+                                Output::Print(_u("FixedNewObj: function %s (%s) ctor cache for %s (%s) about to be cloned has unlocked inline slot count: guard value = 0x%p, type = 0x%p, slots = %d, inline slots = %d\n"),
+                                    functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
+                                    functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"),
+                                    runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->GetType(),
+                                    runtimeConstructorCache->GetSlotCount(), runtimeConstructorCache->GetInlineSlotCount());
+                                Output::Flush();
+                            }
+                        }
+#endif
+                        runtimeConstructorCache->GetType()->GetTypeHandler()->EnsureInlineSlotCapacityIsLocked();
+                        runtimeConstructorCache->UpdateInlineSlotCount();
+                    }
+
+                    // We must keep the runtime cache alive as long as this entry point exists and may try to dereference it.
+                    entryPoint->RegisterConstructorCache(runtimeConstructorCache, recycler);
+                    ctorCache = RecyclerNew(recycler, JITTimeConstructorCache, functionObject, runtimeConstructorCache);
+
+                    if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
+                    {
+                        char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+                        char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+
+                        Output::Print(_u("FixedNewObj: function %s (%s) cloning ctor cache for %s (%s): guard value = 0x%p, type = 0x%p, slots = %d, inline slots = %d\n"),
+                            functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
+                            functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
+                            runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->IsNormal() ? runtimeConstructorCache->GetType() : nullptr,
+                            runtimeConstructorCache->GetSlotCount(), runtimeConstructorCache->GetInlineSlotCount());
+                        Output::Flush();
+                    }
+                }
+                else
+                {
+                    if (!runtimeConstructorCache->IsDefault())
+                    {
+                        if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
+                        {
+                            char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+                            char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
+
+                            Output::Print(_u("FixedNewObj: function %s (%s) skipping ctor cache for %s (%s), because %s (guard value = 0x%p, script context = %p).\n"),
+                                functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
+                                functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
+                                runtimeConstructorCache->IsEmpty() ? _u("cache is empty (or has been cleared)") :
+                                runtimeConstructorCache->IsInvalidated() ? _u("cache is invalidated") :
+                                runtimeConstructorCache->SkipDefaultNewObject() ? _u("default new object isn't needed") :
+                                runtimeConstructorCache->NeedsTypeUpdate() ? _u("cache needs to be updated") :
+                                runtimeConstructorCache->NeedsUpdateAfterCtor() ? _u("cache needs update after ctor") :
+                                runtimeConstructorCache->IsPolymorphic() ? _u("cache is polymorphic") :
+                                runtimeConstructorCache->GetScriptContext() != functionBody->GetScriptContext() ? _u("script context mismatch") : _u("of an unexpected situation"),
+                                runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->GetScriptContext());
+                            Output::Flush();
+                        }
+                    }
+                }
+
+                isBuiltIn = Js::JavascriptLibrary::GetBuiltinFunctionForPropId(propertyId) != Js::BuiltinFunction::None;
+            }
+
+            if (fixedProperty != nullptr)
+            {
+                Assert(fieldValue == nullptr || fieldValue == fixedProperty);
+                fieldValue = fixedProperty;
+                isFieldValueFixed = true;
+                keepFieldValue = true;
+            }
+        }
+    }
+
+    FixedFieldInfo * fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, 1);
+
+    FixedFieldInfo::PopulateFixedField(type, fieldValue, &fixedFieldInfoArray[0]);
+
+    ObjTypeSpecFldInfo* info;
+
+    // If we stress equivalent object type spec, let's pretend that every inline cache was polymorphic and equivalent.
+    bool forcePoly = false;
+    if ((!PHASE_OFF(Js::EquivObjTypeSpecByDefaultPhase, topFunctionBody) ||
+        PHASE_STRESS(Js::EquivObjTypeSpecPhase, topFunctionBody))
+        && !PHASE_OFF(Js::EquivObjTypeSpecPhase, topFunctionBody))
+    {
+        Assert(topFunctionBody->HasDynamicProfileInfo());
+        auto profileData = topFunctionBody->GetAnyDynamicProfileInfo();
+        // We only support equivalent fixed fields on loads from prototype, and no equivalence on missing properties
+        forcePoly |= !profileData->IsEquivalentObjTypeSpecDisabled() && (!isFieldValueFixed || isProto) && !isMissing;
+    }
+
+    if (isFieldValueFixed)
+    {
+        // Fixed field checks allow us to assume a specific type ID, but the assumption is only
+        // valid if we lock the type. Otherwise, the type ID may change out from under us without
+        // evolving the type.
+        if (Js::DynamicType::Is(type->GetTypeId()))
+        {
+            Js::DynamicType *dynamicType = static_cast<Js::DynamicType*>(type);
+            if (!dynamicType->GetIsLocked())
+            {
+                dynamicType->LockType();
+            }
+        }
+    }
+
+    JITType * jitTypeWithoutProperty = nullptr;
+    if (typeWithoutProperty)
+    {
+        jitTypeWithoutProperty = RecyclerNew(recycler, JITType);
+        JITType::BuildFromJsType(typeWithoutProperty, jitTypeWithoutProperty);
+    }
+    if (forcePoly)
+    {
+        uint16 typeCount = 1;
+        JITTypeHolder* types = RecyclerNewArray(recycler, JITTypeHolder, typeCount);
+        types[0].t = RecyclerNew(recycler, JITType);
+        JITType::BuildFromJsType(type, types[0].t);
+        Js::EquivalentTypeSet* typeSet = RecyclerNew(recycler, Js::EquivalentTypeSet, types, typeCount);
+
+        info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
+            id, type->GetTypeId(), jitTypeWithoutProperty, typeSet, usesAuxSlot, isProto, isAccessor, isFieldValueFixed, keepFieldValue, false/*doesntHaveEquivalence*/, false, slotIndex, propertyId,
+            prototypeObject, propertyGuard, ctorCache, fixedFieldInfoArray, 1);
+
+        if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
+        {
+            const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
+            Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type set: 0x%p\n"),
+                id, propertyRecord->GetBuffer(), propertyId, slotIndex, type);
+            Output::Flush();
+        }
+    }
+    else
+    {
+        info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
+            id, type->GetTypeId(), jitTypeWithoutProperty, usesAuxSlot, isProto, isAccessor, isFieldValueFixed, keepFieldValue, isBuiltIn, slotIndex, propertyId,
+            prototypeObject, propertyGuard, ctorCache, fixedFieldInfoArray);
+
+        if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
+        {
+            const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
+            Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type: 0x%p\n"),
+                id, propertyRecord->GetBuffer(), propertyId, slotIndex, type);
+            Output::Flush();
+        }
+    }
+
+    return info;
+}
+
+ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, Js::PolymorphicInlineCache* cache, uint cacheId,
+    Js::EntryPointInfo *entryPoint, Js::FunctionBody* const topFunctionBody, Js::FunctionBody *const functionBody, Js::FieldAccessStatsPtr inlineCacheStats)
+{
+
+#ifdef FIELD_ACCESS_STATS
+#define IncInlineCacheCount(counter) if (inlineCacheStats) { inlineCacheStats->counter++; }
+#else
+#define IncInlineCacheCount(counter)
+#endif
+
+    Assert(topFunctionBody->HasDynamicProfileInfo());
+    auto profileData = topFunctionBody->GetAnyDynamicProfileInfo();
+
+    bool gatherDataForInlining = cache->GetCloneForJitTimeUse() && functionBody->PolyInliningUsingFixedMethodsAllowedByConfigFlags(topFunctionBody);
+
+    if (PHASE_OFF(Js::EquivObjTypeSpecPhase, topFunctionBody) || profileData->IsEquivalentObjTypeSpecDisabled())
+    {
+        if (!gatherDataForInlining)
+        {
+            return nullptr;
+        }
+    }
+
+    Assert(cache->GetSize() < UINT16_MAX);
+    Js::InlineCache* inlineCaches = cache->GetInlineCaches();
+    Js::DynamicObject* prototypeObject = nullptr;
+    Js::DynamicObject* accessorOwnerObject = nullptr;
+    Js::TypeId typeId = Js::TypeIds_Limit;
+    uint16 polyCacheSize = (uint16)cache->GetSize();
+    uint16 firstNonEmptyCacheIndex = UINT16_MAX;
+    uint16 slotIndex = 0;
+    bool areEquivalent = true;
+    bool usesAuxSlot = false;
+    bool isProto = false;
+    bool isAccessor = false;
+    bool isGetterAccessor = false;
+    bool isAccessorOnProto = false;
+
+    bool stress = PHASE_STRESS(Js::EquivObjTypeSpecPhase, topFunctionBody);
+    bool areStressEquivalent = stress;
+
+    uint16 typeCount = 0;
+    for (uint16 i = 0; (areEquivalent || stress || gatherDataForInlining) && i < polyCacheSize; i++)
+    {
+        Js::InlineCache& inlineCache = inlineCaches[i];
+        if (inlineCache.IsEmpty()) continue;
+
+        if (firstNonEmptyCacheIndex == UINT16_MAX)
+        {
+            if (inlineCache.IsLocal())
+            {
+                typeId = TypeWithoutAuxSlotTag(inlineCache.u.local.type)->GetTypeId();
+                usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.local.type);
+                slotIndex = inlineCache.u.local.slotIndex;
+                // We don't support equivalent object type spec for adding properties.
+                areEquivalent = inlineCache.u.local.typeWithoutProperty == nullptr;
+                gatherDataForInlining = false;
+            }
+            // Missing properties cannot be treated as equivalent, because for objects with SDTH or DTH, we don't change the object's type
+            // when we add a property.  We also don't invalidate proto inline caches (and guards) unless the property being added exists on the proto chain.
+            // Missing properties by definition do not exist on the proto chain, so in the end we could have an EquivalentObjTypeSpec cache hit on a
+            // property that once was missing, but has since been added. (See OS Bugs 280582).
+            else if (inlineCache.IsProto() && !inlineCache.u.proto.isMissing)
+            {
+                isProto = true;
+                typeId = TypeWithoutAuxSlotTag(inlineCache.u.proto.type)->GetTypeId();
+                usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.proto.type);
+                slotIndex = inlineCache.u.proto.slotIndex;
+                prototypeObject = inlineCache.u.proto.prototypeObject;
+            }
+            else
+            {
+                if (!PHASE_OFF(Js::FixAccessorPropsPhase, functionBody))
+                {
+                    isAccessor = true;
+                    isGetterAccessor = inlineCache.IsGetterAccessor();
+                    isAccessorOnProto = inlineCache.u.accessor.isOnProto;
+                    accessorOwnerObject = inlineCache.u.accessor.object;
+                    typeId = TypeWithoutAuxSlotTag(inlineCache.u.accessor.type)->GetTypeId();
+                    usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.accessor.type);
+                    slotIndex = inlineCache.u.accessor.slotIndex;
+                }
+                else
+                {
+                    areEquivalent = false;
+                    areStressEquivalent = false;
+                }
+                gatherDataForInlining = false;
+            }
+
+            // If we're stressing equivalent object type spec then let's keep trying to find a cache that we could use.
+            if (!stress || areStressEquivalent)
+            {
+                firstNonEmptyCacheIndex = i;
+            }
+        }
+        else
+        {
+            if (inlineCache.IsLocal())
+            {
+                if (isProto || isAccessor || inlineCache.u.local.typeWithoutProperty != nullptr || slotIndex != inlineCache.u.local.slotIndex ||
+                    typeId != TypeWithoutAuxSlotTag(inlineCache.u.local.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.local.type))
+                {
+                    areEquivalent = false;
+                }
+                gatherDataForInlining = false;
+            }
+            else if (inlineCache.IsProto())
+            {
+                if (!isProto || isAccessor || prototypeObject != inlineCache.u.proto.prototypeObject || slotIndex != inlineCache.u.proto.slotIndex ||
+                    typeId != TypeWithoutAuxSlotTag(inlineCache.u.proto.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.proto.type))
+                {
+                    areEquivalent = false;
+                }
+            }
+            else
+            {
+                // Supporting equivalent obj type spec only for those polymorphic accessor property operations for which
+                // 1. the property is on the same prototype, and
+                // 2. the types are equivalent.
+                //
+                // This is done to keep the equivalence check helper as-is
+                if (!isAccessor || isGetterAccessor != inlineCache.IsGetterAccessor() || !isAccessorOnProto || !inlineCache.u.accessor.isOnProto || accessorOwnerObject != inlineCache.u.accessor.object ||
+                    slotIndex != inlineCache.u.accessor.slotIndex || typeId != TypeWithoutAuxSlotTag(inlineCache.u.accessor.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.accessor.type))
+                {
+                    areEquivalent = false;
+                }
+                gatherDataForInlining = false;
+            }
+        }
+        typeCount++;
+    }
+
+    if (firstNonEmptyCacheIndex == UINT16_MAX)
+    {
+        IncInlineCacheCount(emptyPolyInlineCacheCount);
+        return nullptr;
+    }
+
+    if (cache->GetIgnoreForEquivalentObjTypeSpec())
+    {
+        areEquivalent = areStressEquivalent = false;
+    }
+
+    gatherDataForInlining = gatherDataForInlining && (typeCount <= 4); // Only support 4-way (max) polymorphic inlining
+    if (!areEquivalent && !areStressEquivalent)
+    {
+        IncInlineCacheCount(nonEquivPolyInlineCacheCount);
+        cache->SetIgnoreForEquivalentObjTypeSpec(true);
+        if (!gatherDataForInlining)
+        {
+            return nullptr;
+        }
+    }
+
+    Assert(firstNonEmptyCacheIndex < polyCacheSize);
+    Assert(typeId != Js::TypeIds_Limit);
+    IncInlineCacheCount(equivPolyInlineCacheCount);
+
+    // If we're stressing equivalent object type spec and the types are not equivalent, let's grab the first one only.
+    if (stress && (areEquivalent != areStressEquivalent))
+    {
+        polyCacheSize = firstNonEmptyCacheIndex + 1;
+    }
+
+    Js::ScriptContext* scriptContext = functionBody->GetScriptContext();
+    Recycler* recycler = scriptContext->GetRecycler();
+
+    uint16 fixedFunctionCount = 0;
+
+    // Need to create a local array here and not allocate one from the recycler,
+    // as the allocation may trigger a GC which can clear the inline caches.
+    FixedFieldInfo localFixedFieldInfoArray[Js::DynamicProfileInfo::maxPolymorphicInliningSize] = {};
+
+    // For polymorphic field loads we only support fixed functions on prototypes. This helps keep the equivalence check helper simple.
+    // Since all types in the polymorphic cache share the same prototype, it's enough to grab the fixed function from the prototype object.
+    Js::Var fixedProperty = nullptr;
+    if ((isProto || isAccessorOnProto) && (areEquivalent || areStressEquivalent))
+    {
+        const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(cacheId));
+        if (isProto)
+        {
+            prototypeObject->GetDynamicType()->GetTypeHandler()->TryUseFixedProperty(propertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedMethodProperty | Js::FixedPropertyKind::FixedDataProperty), scriptContext);
+        }
+        else if (isAccessorOnProto)
+        {
+            accessorOwnerObject->GetDynamicType()->GetTypeHandler()->TryUseFixedAccessor(propertyRecord, &fixedProperty, Js::FixedPropertyKind::FixedAccessorProperty, isGetterAccessor, scriptContext);
+        }
+
+        FixedFieldInfo::PopulateFixedField(nullptr, fixedProperty, &localFixedFieldInfoArray[0]);
+
+        // TODO (ObjTypeSpec): Enable constructor caches on equivalent polymorphic field loads with fixed functions.
+    }
+
+    // Let's get the types.
+    Js::Type* localTypes[MaxPolymorphicInlineCacheSize];
+
+    uint16 typeNumber = 0;
+    Js::JavascriptFunction* fixedFunctionObject = nullptr;
+    for (uint16 i = firstNonEmptyCacheIndex; i < polyCacheSize; i++)
+    {
+        Js::InlineCache& inlineCache = inlineCaches[i];
+        if (inlineCache.IsEmpty()) continue;
+
+        localTypes[typeNumber] = inlineCache.IsLocal() ? TypeWithoutAuxSlotTag(inlineCache.u.local.type) :
+            inlineCache.IsProto() ? TypeWithoutAuxSlotTag(inlineCache.u.proto.type) :
+            TypeWithoutAuxSlotTag(inlineCache.u.accessor.type);
+
+        if (gatherDataForInlining)
+        {
+            inlineCache.TryGetFixedMethodFromCache(functionBody, cacheId, &fixedFunctionObject);
+            if (!fixedFunctionObject || !fixedFunctionObject->GetFunctionInfo()->HasBody())
+            {
+                if (!(areEquivalent || areStressEquivalent))
+                {
+                    // If we reach here only because we are gathering data for inlining, and one of the Inline Caches doesn't have a fixedfunction object, return.
+                    return nullptr;
+                }
+                else
+                {
+                    // If one of the inline caches doesn't have a fixed function object, abort gathering inlining data.
+                    gatherDataForInlining = false;
+                    typeNumber++;
+                    continue;
+                }
+            }
+
+            // We got a fixed function object from the cache.
+
+            FixedFieldInfo::PopulateFixedField(localTypes[typeNumber], fixedFunctionObject, &localFixedFieldInfoArray[typeNumber]);
+
+            fixedFunctionCount++;
+        }
+
+        typeNumber++;
+    }
+
+    if (isAccessor && gatherDataForInlining)
+    {
+        Assert(fixedFunctionCount <= 1);
+    }
+
+    if (stress && (areEquivalent != areStressEquivalent))
+    {
+        typeCount = 1;
+    }
+
+    AnalysisAssert(typeNumber == typeCount);
+
+    // Now that we've copied all material info into local variables, we can start allocating without fear
+    // that a garbage collection will clear any of the live inline caches.
+
+    FixedFieldInfo* fixedFieldInfoArray;
+    if (gatherDataForInlining)
+    {
+        fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, fixedFunctionCount);
+        memcpy(fixedFieldInfoArray, localFixedFieldInfoArray, fixedFunctionCount * sizeof(FixedFieldInfo));
+    }
+    else
+    {
+        fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, 1);
+        memcpy(fixedFieldInfoArray, localFixedFieldInfoArray, 1 * sizeof(FixedFieldInfo));
+    }
+
+    Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(cacheId);
+    Js::PropertyGuard* propertyGuard = entryPoint->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.
+    bool hasFixedValue = gatherDataForInlining ||
+        ((isProto || isAccessorOnProto) && (areEquivalent || areStressEquivalent) && localFixedFieldInfoArray[0].GetFieldValue());
+
+    bool doesntHaveEquivalence = !(areEquivalent || areStressEquivalent);
+
+    Js::EquivalentTypeSet* typeSet = nullptr;
+    auto jitTransferData = entryPoint->GetJitTransferData();
+    Assert(jitTransferData != nullptr);
+    if (areEquivalent || areStressEquivalent)
+    {
+        JITTypeHolder* types = RecyclerNewArray(recycler, JITTypeHolder, typeCount);
+        for (uint16 i = 0; i < typeCount; i++)
+        {
+            jitTransferData->AddJitTimeTypeRef(localTypes[i], recycler);
+            if (hasFixedValue)
+            {
+                // Fixed field checks allow us to assume a specific type ID, but the assumption is only
+                // valid if we lock the type. Otherwise, the type ID may change out from under us without
+                // evolving the type.
+                if (Js::DynamicType::Is(localTypes[i]->GetTypeId()))
+                {
+                    Js::DynamicType *dynamicType = static_cast<Js::DynamicType*>(localTypes[i]);
+                    if (!dynamicType->GetIsLocked())
+                    {
+                        dynamicType->LockType();
+                    }
+                }
+            }
+            // TODO: OOP JIT, consider putting these inline
+            types[i].t = RecyclerNew(recycler, JITType);
+            __analysis_assume(localTypes[i] != nullptr);
+            JITType::BuildFromJsType(localTypes[i], types[i].t);
+        }
+        typeSet = RecyclerNew(recycler, Js::EquivalentTypeSet, types, typeCount);
+    }
+
+    ObjTypeSpecFldInfo* info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
+        id, typeId, nullptr, typeSet, usesAuxSlot, isProto, isAccessor, hasFixedValue, hasFixedValue, doesntHaveEquivalence, true, slotIndex, propertyId,
+        prototypeObject, propertyGuard, nullptr, fixedFieldInfoArray, fixedFunctionCount/*, nullptr, nullptr, nullptr*/);
+
+    if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
+    {
+        if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
+        {
+            if (typeSet)
+            {
+                const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
+                Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type set: "),
+                    id, propertyRecord->GetBuffer(), propertyId, slotIndex);
+                for (uint16 ti = 0; ti < typeCount - 1; ti++)
+                {
+                    Output::Print(_u("0x%p, "), typeSet->GetType(ti));
+                }
+                Output::Print(_u("0x%p\n"), typeSet->GetType(typeCount - 1));
+                Output::Flush();
+            }
+        }
+    }
+
+    return info;
+
+#undef IncInlineCacheCount
+}
+
+ObjTypeSpecFldInfoFlags
+ObjTypeSpecFldInfo::GetFlags() const
+{
+    return (ObjTypeSpecFldInfoFlags)m_data.flags;
+}
+
+ObjTypeSpecFldInfoFlags *
+ObjTypeSpecFldInfo::GetFlagsPtr()
+{
+    return (ObjTypeSpecFldInfoFlags*)&m_data.flags;
+}
+
+ObjTypeSpecFldInfoArray::ObjTypeSpecFldInfoArray()
+    : infoArray(nullptr)
+#if DBG
+    , infoCount(0)
+#endif
+{
+}
+
+void ObjTypeSpecFldInfoArray::EnsureArray(Recycler *const recycler, Js::FunctionBody *const functionBody)
+{
+    Assert(recycler != nullptr);
+    Assert(functionBody != nullptr);
+    Assert(functionBody->GetInlineCacheCount() != 0);
+
+    if (this->infoArray)
+    {
+        Assert(functionBody->GetInlineCacheCount() == this->infoCount);
+        return;
+    }
+
+    this->infoArray = RecyclerNewArrayZ(recycler, ObjTypeSpecFldInfo*, functionBody->GetInlineCacheCount());
+#if DBG
+    this->infoCount = functionBody->GetInlineCacheCount();
+#endif
+}
+
+ObjTypeSpecFldInfo* ObjTypeSpecFldInfoArray::GetInfo(Js::FunctionBody *const functionBody, const uint index) const
+{
+    Assert(functionBody);
+    Assert(this->infoArray == nullptr || functionBody->GetInlineCacheCount() == this->infoCount);
+    Assert(index < functionBody->GetInlineCacheCount());
+    return this->infoArray ? this->infoArray[index] : nullptr;
+}
+
+void ObjTypeSpecFldInfoArray::SetInfo(Recycler *const recycler, Js::FunctionBody *const functionBody,
+    const uint index, ObjTypeSpecFldInfo* info)
+{
+    Assert(recycler);
+    Assert(functionBody);
+    Assert(this->infoArray == nullptr || functionBody->GetInlineCacheCount() == this->infoCount);
+    Assert(index < functionBody->GetInlineCacheCount());
+    Assert(info);
+
+    EnsureArray(recycler, functionBody);
+    this->infoArray[index] = info;
+}
+
+void ObjTypeSpecFldInfoArray::Reset()
+{
+    this->infoArray = nullptr;
+#if DBG
+    this->infoCount = 0;
+#endif
+}

+ 258 - 0
lib/Backend/ObjTypeSpecFldInfo.h

@@ -0,0 +1,258 @@
+//-------------------------------------------------------------------------------------------------------
+// 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
+
+#define InitialObjTypeSpecFldInfoFlagValue 0x01
+
+// Union with uint16 flags for fast default initialization
+union ObjTypeSpecFldInfoFlags
+{
+    struct
+    {
+        bool falseReferencePreventionBit : 1;
+        bool isPolymorphic : 1;
+        bool isRootObjectNonConfigurableField : 1;
+        bool isRootObjectNonConfigurableFieldLoad : 1;
+        bool usesAuxSlot : 1;
+        bool isLocal : 1;
+        bool isLoadedFromProto : 1;
+        bool usesAccessor : 1;
+        bool hasFixedValue : 1;
+        bool keepFieldValue : 1;
+        bool isBeingStored : 1;
+        bool isBeingAdded : 1;
+        bool doesntHaveEquivalence : 1;
+        bool isBuiltIn : 1;
+    };
+    struct
+    {
+        uint16 flags;
+    };
+    ObjTypeSpecFldInfoFlags(uint16 flags) : flags(flags) { }
+};
+
+class ObjTypeSpecFldInfo
+{
+public:
+    ObjTypeSpecFldInfo()
+    {
+        m_data.id = 0;
+        m_data.typeId = Js::TypeIds_Limit;
+        m_data.typeSet = nullptr;
+        m_data.initialType = nullptr;
+        m_data.flags = InitialObjTypeSpecFldInfoFlagValue;
+        m_data.slotIndex = Js::Constants::NoSlot;
+        m_data.propertyId = Js::Constants::NoProperty;
+        m_data.protoObjectAddr = 0;
+        m_data.propertyGuardValueAddr = 0;
+        m_data.ctorCache = nullptr;
+        m_data.fixedFieldCount = 0;
+        m_data.fixedFieldInfoArraySize = 0;
+        m_data.fixedFieldInfoArray = nullptr;
+    }
+
+    ObjTypeSpecFldInfo(uint id, Js::TypeId typeId, JITType* initialType,
+        bool usesAuxSlot, bool isLoadedFromProto, bool usesAccessor, bool isFieldValueFixed, bool keepFieldValue, bool isBuiltIn,
+        uint16 slotIndex, Js::PropertyId propertyId, Js::DynamicObject* protoObject, Js::PropertyGuard* propertyGuard,
+        JITTimeConstructorCache* ctorCache, FixedFieldInfo* fixedFieldInfoArray)
+    {
+        ObjTypeSpecFldInfoFlags flags(InitialObjTypeSpecFldInfoFlagValue);
+        flags.isPolymorphic = false;
+        flags.usesAuxSlot = usesAuxSlot;
+        flags.isLocal = !isLoadedFromProto && !usesAccessor;
+        flags.isLoadedFromProto = isLoadedFromProto;
+        flags.usesAccessor = usesAccessor;
+        flags.hasFixedValue = isFieldValueFixed;
+        flags.keepFieldValue = keepFieldValue;
+        flags.isBeingAdded = initialType != nullptr;
+        flags.doesntHaveEquivalence = true; // doesn't mean anything for data from a monomorphic cache
+        flags.isBuiltIn = isBuiltIn;
+        m_data.flags = flags.flags;
+
+        m_data.id = id;
+        m_data.typeId = typeId;
+        m_data.typeSet = nullptr;
+        m_data.initialType = initialType->GetData();
+        m_data.slotIndex = slotIndex;
+        m_data.propertyId = propertyId;
+        m_data.protoObjectAddr = (intptr_t)protoObject;
+        m_data.propertyGuardValueAddr = (intptr_t)propertyGuard->GetAddressOfValue();
+        m_data.ctorCache = ctorCache->GetData();
+        m_data.fixedFieldCount = 1;
+        m_data.fixedFieldInfoArraySize = 1;
+        m_data.fixedFieldInfoArray = fixedFieldInfoArray->GetRaw();
+    }
+
+    ObjTypeSpecFldInfo(uint id, Js::TypeId typeId, JITType* initialType, Js::EquivalentTypeSet* typeSet,
+        bool usesAuxSlot, bool isLoadedFromProto, bool usesAccessor, bool isFieldValueFixed, bool keepFieldValue, bool doesntHaveEquivalence, bool isPolymorphic,
+        uint16 slotIndex, Js::PropertyId propertyId, Js::DynamicObject* protoObject, Js::PropertyGuard* propertyGuard,
+        JITTimeConstructorCache* ctorCache, FixedFieldInfo* fixedFieldInfoArray, uint16 fixedFieldCount)
+    {
+        ObjTypeSpecFldInfoFlags flags(InitialObjTypeSpecFldInfoFlagValue);
+        flags.isPolymorphic = isPolymorphic;
+        flags.usesAuxSlot = usesAuxSlot;
+        flags.isLocal = !isLoadedFromProto && !usesAccessor;
+        flags.isLoadedFromProto = isLoadedFromProto;
+        flags.usesAccessor = usesAccessor;
+        flags.hasFixedValue = isFieldValueFixed;
+        flags.keepFieldValue = keepFieldValue;
+        flags.isBeingAdded = initialType != nullptr;
+        flags.doesntHaveEquivalence = doesntHaveEquivalence;
+        flags.isBuiltIn = false;
+        m_data.flags = flags.flags;
+
+        m_data.id = id;
+        m_data.typeId = typeId;
+        m_data.typeSet = (EquivalentTypeSetIDL*)typeSet;
+        m_data.initialType = initialType->GetData();
+        m_data.slotIndex = slotIndex;
+        m_data.propertyId = propertyId;
+        m_data.protoObjectAddr = (intptr_t)protoObject;
+        m_data.propertyGuardValueAddr = (intptr_t)propertyGuard->GetAddressOfValue();
+        m_data.ctorCache = ctorCache->GetData();
+        m_data.fixedFieldCount = fixedFieldCount;
+        m_data.fixedFieldInfoArraySize = fixedFieldCount > 0 ? fixedFieldCount : 1;
+        m_data.fixedFieldInfoArray = fixedFieldInfoArray->GetRaw();
+    }
+
+    bool UsesAuxSlot() const;
+    bool UsesAccessor() const;
+    bool IsRootObjectNonConfigurableFieldLoad() const;
+    bool HasEquivalentTypeSet() const;
+    bool DoesntHaveEquivalence() const;
+    bool IsPoly() const;
+    bool IsMono() const;
+    bool IsBuiltIn() const;
+    bool IsLoadedFromProto() const;
+    bool HasFixedValue() const;
+    bool IsBeingStored() const;
+    bool IsBeingAdded() const;
+    bool IsRootObjectNonConfigurableField() const;
+    bool HasInitialType() const;
+    bool IsMonoObjTypeSpecCandidate() const;
+    bool IsPolyObjTypeSpecCandidate() const;
+
+    bool GetKeepFieldValue() const
+    {
+        return GetFlags().keepFieldValue;
+    }
+
+    void SetFieldValue(Js::Var value)
+    {
+        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
+        m_data.fixedFieldInfoArray[0].fieldValue = (intptr_t)value;
+    }
+
+    bool IsBuiltin() const
+    {
+        return GetFlags().isBuiltIn;
+    }
+
+    void SetRootObjectNonConfigurableField(bool isLoad)
+    {
+        GetFlagsPtr()->isRootObjectNonConfigurableField = true;
+        GetFlagsPtr()->isRootObjectNonConfigurableFieldLoad = isLoad;
+    }
+
+    Js::JavascriptFunction* GetFieldValueAsFunctionIfAvailable() const
+    {
+        Assert(!JITManager::GetJITManager()->IsJITServer());
+        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
+
+        if (PHASE_OFF1(Js::ObjTypeSpecPhase)) return nullptr; // TODO: (lei)remove this after obj type spec for OOPJIT implemented
+
+        return m_data.fixedFieldInfoArray[0].fieldValue != 0 && Js::JavascriptFunction::Is((Js::Var)m_data.fixedFieldInfoArray[0].fieldValue) ?
+            Js::JavascriptFunction::FromVar((Js::Var)m_data.fixedFieldInfoArray[0].fieldValue) : nullptr;
+    }
+
+    Js::TypeId GetTypeId() const;
+    Js::TypeId GetTypeId(uint i) const;
+
+    Js::PropertyId GetPropertyId() const;
+    uint16 GetSlotIndex() const;
+    uint16 GetFixedFieldCount() const;
+
+    uint GetObjTypeSpecFldId() const;
+
+    intptr_t GetProtoObject() const;
+    intptr_t GetFieldValue(uint i) const;
+    intptr_t GetPropertyGuardValueAddr() const;
+    intptr_t GetFieldValueAsFixedDataIfAvailable() const;
+
+    JITTimeConstructorCache * GetCtorCache() const;
+
+    Js::EquivalentTypeSet * GetEquivalentTypeSet() const;
+    JITTypeHolder GetType() const;
+    JITTypeHolder GetType(uint i) const;
+    JITTypeHolder GetInitialType() const;
+    JITTypeHolder GetFirstEquivalentType() const;
+
+    FixedFieldInfo * GetFixedFieldIfAvailableAsFixedFunction();
+    FixedFieldInfo * GetFixedFieldIfAvailableAsFixedFunction(uint i);
+    FixedFieldInfo * GetFixedFieldInfoArray();
+
+    void SetIsBeingStored(bool value); // REVIEW: this doesn't flow out of JIT, should it?
+
+    ObjTypeSpecFldIDL * GetRaw() { return &m_data; }
+
+    static ObjTypeSpecFldInfo* CreateFrom(uint id, Js::InlineCache* cache, uint cacheId,
+        Js::EntryPointInfo *entryPoint, Js::FunctionBody* const topFunctionBody, Js::FunctionBody *const functionBody, Js::FieldAccessStatsPtr inlineCacheStats);
+
+    static ObjTypeSpecFldInfo* CreateFrom(uint id, Js::PolymorphicInlineCache* cache, uint cacheId,
+        Js::EntryPointInfo *entryPoint, Js::FunctionBody* const topFunctionBody, Js::FunctionBody *const functionBody, Js::FieldAccessStatsPtr inlineCacheStats);
+
+    // TODO: OOP JIT, implement this
+    char16* GetCacheLayoutString() { __debugbreak(); return nullptr; }
+
+private:
+    ObjTypeSpecFldInfoFlags GetFlags() const;
+    ObjTypeSpecFldInfoFlags * GetFlagsPtr();
+
+    ObjTypeSpecFldIDL m_data;
+};
+
+class ObjTypeSpecFldInfoArray
+{
+private:
+    ObjTypeSpecFldInfo** infoArray;
+#if DBG
+    uint infoCount;
+#endif
+public:
+    ObjTypeSpecFldInfoArray();
+
+private:
+    void EnsureArray(Recycler *const recycler, Js::FunctionBody *const functionBody);
+
+public:
+    ObjTypeSpecFldInfo* GetInfo(Js::FunctionBody *const functionBody, const uint index) const;
+    ObjTypeSpecFldInfo* GetInfo(const uint index) const;
+    ObjTypeSpecFldInfo** GetInfoArray() const { return infoArray; }
+
+    void SetInfo(Recycler *const recycler, Js::FunctionBody *const functionBody,
+        const uint index, ObjTypeSpecFldInfo* info);
+
+    void Reset();
+
+    template <class Fn>
+    void Map(Fn fn, uint count) const
+    {
+        if (this->infoArray != nullptr)
+        {
+            for (uint i = 0; i < count; i++)
+            {
+                ObjTypeSpecFldInfo* info = this->infoArray[i];
+
+                if (info != nullptr)
+                {
+                    fn(info);
+                }
+            }
+        }
+    };
+
+    PREVENT_COPY(ObjTypeSpecFldInfoArray)
+};

+ 2 - 2
lib/Backend/Opnd.cpp

@@ -835,7 +835,7 @@ PropertySymOpnd::New(PropertySym *propertySym, IRType type, Func *func)
 }
 
 void
-PropertySymOpnd::Init(uint inlineCacheIndex, intptr_t runtimeInlineCache, JITTimePolymorphicInlineCache * runtimePolymorphicInlineCache, JITObjTypeSpecFldInfo* objTypeSpecFldInfo, byte polyCacheUtil)
+PropertySymOpnd::Init(uint inlineCacheIndex, intptr_t runtimeInlineCache, JITTimePolymorphicInlineCache * runtimePolymorphicInlineCache, ObjTypeSpecFldInfo* objTypeSpecFldInfo, byte polyCacheUtil)
 {
     this->m_inlineCacheIndex = inlineCacheIndex;
     this->m_runtimeInlineCache = runtimeInlineCache;
@@ -2970,7 +2970,7 @@ Opnd::Dump(IRDumpFlags flags, Func *func)
                         {
                             Output::Print(_u(","));
                         }
-                        const JITObjTypeSpecFldInfo* propertyOpInfo = func->GetTopFunc()->GetGlobalObjTypeSpecFldInfo(propertyOpId);
+                        const ObjTypeSpecFldInfo* propertyOpInfo = func->GetTopFunc()->GetGlobalObjTypeSpecFldInfo(propertyOpId);
                         if (!JITManager::GetJITManager()->IsOOPJITEnabled())
                         {
                             Output::Print(_u("%s"), func->GetInProcThreadContext()->GetPropertyRecord(propertyOpInfo->GetPropertyId())->GetBuffer(), propertyOpId);

+ 7 - 7
lib/Backend/Opnd.h

@@ -557,7 +557,7 @@ public:
 
 private:
     static PropertySymOpnd * New(PropertySym *propertySym, IRType type, Func *func);
-    void Init(uint inlineCacheIndex, intptr_t runtimeInlineCache, JITTimePolymorphicInlineCache * runtimePolymorphicInlineCache, JITObjTypeSpecFldInfo* objTypeSpecFldInfo, byte polyCacheUtil);
+    void Init(uint inlineCacheIndex, intptr_t runtimeInlineCache, JITTimePolymorphicInlineCache * runtimePolymorphicInlineCache, ObjTypeSpecFldInfo* objTypeSpecFldInfo, byte polyCacheUtil);
 #if DBG
     virtual bool      DbgIsPropertySymOpnd() const override { return true; }
 #endif
@@ -566,7 +566,7 @@ public:
     intptr_t m_runtimeInlineCache;
     JITTimePolymorphicInlineCache* m_runtimePolymorphicInlineCache;
 private:
-    JITObjTypeSpecFldInfo* objTypeSpecFldInfo;
+    ObjTypeSpecFldInfo* objTypeSpecFldInfo;
 public:
     JITTypeHolder finalType;
     JITTypeHolder monoGuardType;
@@ -626,7 +626,7 @@ public:
         return this->objTypeSpecFldInfo != nullptr;
     }
 
-    void SetObjTypeSpecFldInfo(JITObjTypeSpecFldInfo *const objTypeSpecFldInfo)
+    void SetObjTypeSpecFldInfo(ObjTypeSpecFldInfo *const objTypeSpecFldInfo)
     {
         this->objTypeSpecFldInfo = objTypeSpecFldInfo;
 
@@ -661,7 +661,7 @@ public:
         return false;
     }
 
-    JITObjTypeSpecFldInfo* GetObjTypeSpecInfo() const
+    ObjTypeSpecFldInfo* GetObjTypeSpecInfo() const
     {
         return this->objTypeSpecFldInfo;
     }
@@ -811,13 +811,13 @@ public:
         return this->objTypeSpecFldInfo->GetProtoObject();
     }
 
-    JITTimeFixedField * GetFixedFunction() const
+    FixedFieldInfo * GetFixedFunction() const
     {
         Assert(HasObjTypeSpecFldInfo());
         return this->objTypeSpecFldInfo->GetFixedFieldIfAvailableAsFixedFunction();
     }
 
-    JITTimeFixedField * GetFixedFunction(uint i) const
+    FixedFieldInfo * GetFixedFunction(uint i) const
     {
         Assert(HasObjTypeSpecFldInfo());
         return this->objTypeSpecFldInfo->GetFixedFieldIfAvailableAsFixedFunction(i);
@@ -835,7 +835,7 @@ public:
         return this->objTypeSpecFldInfo->GetFieldValue(i);
     }
 
-    JITTimeFixedField * GetFixedFieldInfoArray()
+    FixedFieldInfo * GetFixedFieldInfoArray()
     {
         Assert(HasObjTypeSpecFldInfo());
         return this->objTypeSpecFldInfo->GetFixedFieldInfoArray();

+ 5 - 7
lib/JITIDL/JITTypes.h

@@ -90,9 +90,10 @@ typedef struct TypeHandlerIDL
 
 typedef struct TypeIDL
 {
+    IDL_Field(boolean) exists;
     IDL_Field(unsigned char) flags;
     IDL_Field(boolean) isShared;
-    IDL_PAD2(0)
+    IDL_PAD1(0)
     IDL_Field(int) typeId;
 
     IDL_Field(CHAKRA_WB_PTR) libAddr;
@@ -119,7 +120,7 @@ typedef struct FixedFieldIDL
     boolean isClassCtor;
     unsigned short valueType;
     unsigned int localFuncId;
-    TypeIDL * type;
+    TypeIDL type;
     CHAKRA_PTR fieldValue;
     CHAKRA_PTR funcInfoAddr;
     CHAKRA_PTR environmentAddr;
@@ -147,13 +148,10 @@ typedef struct JITTimeConstructorCacheIDL
 
 typedef struct ObjTypeSpecFldIDL
 {
-    boolean inUse;
-    IDL_PAD1(0)
     unsigned short flags;
     unsigned short slotIndex;
     unsigned short fixedFieldCount;
     unsigned short fixedFieldInfoArraySize; // 1 (when fixedFieldCount is 0) or fixedFieldCount
-    IDL_PAD2(1)
     int propertyId;
     int typeId;
     unsigned int id;
@@ -611,7 +609,7 @@ typedef struct FunctionJITTimeDataIDL
     unsigned int globalObjTypeSpecFldInfoCount;
     IDL_DEF([size_is(sharedPropGuardCount)]) int * sharedPropertyGuards;
 
-    IDL_DEF([size_is(globalObjTypeSpecFldInfoCount)]) ObjTypeSpecFldIDL * globalObjTypeSpecFldInfoArray;
+    IDL_DEF([size_is(globalObjTypeSpecFldInfoCount)]) ObjTypeSpecFldIDL ** globalObjTypeSpecFldInfoArray;
 
     unsigned int inlineeCount;
     unsigned int ldFldInlineeCount;
@@ -622,7 +620,7 @@ typedef struct FunctionJITTimeDataIDL
 
     X64_PAD4(1)
     unsigned int objTypeSpecFldInfoCount;
-    IDL_DEF([size_is(objTypeSpecFldInfoCount)]) ObjTypeSpecFldIDL * objTypeSpecFldInfoArray;
+    IDL_DEF([size_is(objTypeSpecFldInfoCount)]) ObjTypeSpecFldIDL ** objTypeSpecFldInfoArray;
 
     FunctionJITRuntimeIDL * profiledRuntimeData;
 

+ 0 - 3
lib/Runtime/Language/CMakeLists.txt

@@ -19,7 +19,6 @@ set(CRL_SOURCE_FILES ${CRL_SOURCE_FILES}
     DynamicProfileMutator.cpp
     DynamicProfileStorage.cpp
     ExecutionMode.cpp
-    FunctionCodeGenJitTimeData.cpp
     FunctionCodeGenRuntimeData.cpp
     InlineCache.cpp
     InterpreterStackFrame.cpp
@@ -32,9 +31,7 @@ set(CRL_SOURCE_FILES ${CRL_SOURCE_FILES}
     JavascriptStackWalker.cpp
     ModuleNamespace.cpp
     ModuleNamespaceEnumerator.cpp
-    ObjTypeSpecFldInfo.cpp
     ProfilingHelpers.cpp
-    #ReadOnlyDynamicProfileInfo.cpp
     RuntimeLanguagePch.cpp
     SimdBool16x8Operation.cpp
     SimdBool16x8OperationX86X64.cpp

+ 0 - 4
lib/Runtime/Language/Chakra.Runtime.Language.vcxproj

@@ -86,7 +86,6 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)DynamicProfileMutator.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)DynamicProfileStorage.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ExecutionMode.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)FunctionCodeGenJitTimeData.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)FunctionCodeGenRuntimeData.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)InlineCache.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JavascriptExceptionObject.cpp" />
@@ -172,7 +171,6 @@
       <PrecompiledHeader>Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="$(MSBuildThisFileDirectory)JavascriptNativeOperators.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)ObjTypeSpecFldInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ModuleNamespace.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)SourceTextModuleRecord.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)WAsmjsUtils.cpp" />
@@ -212,7 +210,6 @@
     <ClInclude Include="EvalMapRecord.h" />
     <ClInclude Include="ExecutionMode.h" />
     <ClInclude Include="ExecutionModes.h" />
-    <ClInclude Include="FunctionCodeGenJitTimeData.h" />
     <ClInclude Include="FunctionCodeGenRuntimeData.h" />
     <ClInclude Include="i386\StackFrame.h">
       <ExcludedFromBuild Condition="'$(Platform)'!='Win32'">true</ExcludedFromBuild>
@@ -222,7 +219,6 @@
     <ClInclude Include="JavascriptExceptionOperators.h" />
     <ClInclude Include="JavascriptMathOperators.h" />
     <ClInclude Include="JavascriptNativeOperators.h" />
-    <ClInclude Include="ObjTypeSpecFldInfo.h" />
     <ClInclude Include="ModuleNamespace.h" />
     <ClInclude Include="ModuleNamespaceEnumerator.h" />
     <ClInclude Include="ProfilingHelpers.h" />

+ 0 - 4
lib/Runtime/Language/Chakra.Runtime.Language.vcxproj.filters

@@ -15,7 +15,6 @@
     <ClCompile Include="$(MsBuildThisFileDirectory)DynamicProfileMutator.cpp" />
     <ClCompile Include="$(MsBuildThisFileDirectory)DynamicProfileStorage.cpp" />
     <ClCompile Include="$(MsBuildThisFileDirectory)ExecutionMode.cpp" />
-    <ClCompile Include="$(MsBuildThisFileDirectory)FunctionCodeGenJitTimeData.cpp" />
     <ClCompile Include="$(MsBuildThisFileDirectory)FunctionCodeGenRuntimeData.cpp" />
     <ClCompile Include="$(MsBuildThisFileDirectory)InlineCache.cpp" />
     <ClCompile Include="$(MsBuildThisFileDirectory)JavascriptExceptionOperators.cpp" />
@@ -74,7 +73,6 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)SIMDBool8x16Operation.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)SIMDBool8x16OperationX86X64.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)WAsmjsUtils.cpp" />
-    <ClCompile Include="$(MSBuildThisFileDirectory)ObjTypeSpecFldInfo.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ModuleNamespace.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)SourceTextModuleRecord.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ModuleNamespaceEnumerator.cpp" />
@@ -98,7 +96,6 @@
     <ClInclude Include="EvalMapRecord.h" />
     <ClInclude Include="ExecutionMode.h" />
     <ClInclude Include="ExecutionModes.h" />
-    <ClInclude Include="FunctionCodeGenJitTimeData.h" />
     <ClInclude Include="FunctionCodeGenRuntimeData.h" />
     <ClInclude Include="InlineCache.h" />
     <ClInclude Include="InlineCachePointerArray.h" />
@@ -149,7 +146,6 @@
     <ClInclude Include="SimdBool16x8Operation.h" />
     <ClInclude Include="SimdBool8x16Operation.h" />
     <ClInclude Include="WAsmjsUtils.h" />
-    <ClInclude Include="ObjTypeSpecFldInfo.h" />
     <ClInclude Include="ModuleNamespace.h" />
     <ClInclude Include="ModuleNamespaceEnumerator.h" />
     <ClInclude Include="WebAssemblySource.h" />

+ 0 - 828
lib/Runtime/Language/ObjTypeSpecFldInfo.cpp

@@ -1,828 +0,0 @@
-//-------------------------------------------------------------------------------------------------------
-// Copyright (C) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
-//-------------------------------------------------------------------------------------------------------
-#include "RuntimeLanguagePch.h"
-
-#if ENABLE_NATIVE_CODEGEN
-
-#include "JITType.h"
-#include "JITTimeConstructorCache.h"
-
-namespace Js
-{
-    ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, InlineCache* cache, uint cacheId, EntryPointInfo *entryPoint,
-        FunctionBody* const topFunctionBody, FunctionBody *const functionBody, FieldAccessStatsPtr inlineCacheStats)
-    {
-        if (cache->IsEmpty())
-        {
-            return nullptr;
-        }
-
-        InlineCache localCache(*cache);
-
-        // Need to keep a reference to the types before memory allocation in case they are tagged
-        Type * type = nullptr;
-        Type * typeWithoutProperty = nullptr;
-        Js::Type * propertyOwnerType;
-        bool isLocal = localCache.IsLocal();
-        bool isProto = localCache.IsProto();
-        bool isAccessor = localCache.IsAccessor();
-        bool isGetter = localCache.IsGetterAccessor();
-        if (isLocal)
-        {
-            type = TypeWithoutAuxSlotTag(localCache.u.local.type);
-            if (localCache.u.local.typeWithoutProperty)
-            {
-                typeWithoutProperty = TypeWithoutAuxSlotTag(localCache.u.local.typeWithoutProperty);
-            }
-            propertyOwnerType = type;
-        }
-        else if (isProto)
-        {
-            type = TypeWithoutAuxSlotTag(localCache.u.proto.type);
-            propertyOwnerType = localCache.u.proto.prototypeObject->GetType();
-        }
-        else
-        {
-            if (PHASE_OFF(Js::FixAccessorPropsPhase, functionBody))
-            {
-                return nullptr;
-            }
-
-            type = TypeWithoutAuxSlotTag(localCache.u.accessor.type);
-            propertyOwnerType = localCache.u.accessor.object->GetType();
-        }
-
-        ScriptContext* scriptContext = functionBody->GetScriptContext();
-        Recycler *const recycler = scriptContext->GetRecycler();
-
-        Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(cacheId);
-        uint16 slotIndex = Constants::NoSlot;
-        bool usesAuxSlot = false;
-        DynamicObject* prototypeObject = nullptr;
-        PropertyGuard* propertyGuard = nullptr;
-        JITTimeConstructorCache* ctorCache = nullptr;
-        Var fieldValue = nullptr;
-        bool keepFieldValue = false;
-        bool isFieldValueFixed = false;
-        bool isMissing = false;
-        bool isBuiltIn = false;
-
-        // Save untagged type pointers, remembering whether the original type was tagged.
-        // The type pointers must be untagged so that the types cannot be collected during JIT.
-
-        if (isLocal)
-        {
-            slotIndex = localCache.u.local.slotIndex;
-            if (type != localCache.u.local.type)
-            {
-                usesAuxSlot = true;
-            }
-            if (typeWithoutProperty)
-            {
-                Assert(entryPoint->GetJitTransferData() != nullptr);
-                entryPoint->GetJitTransferData()->AddJitTimeTypeRef(typeWithoutProperty, recycler);
-
-                // 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);
-            }
-        }
-        else if (isProto)
-        {
-            prototypeObject = localCache.u.proto.prototypeObject;
-            slotIndex = localCache.u.proto.slotIndex;
-            if (type != localCache.u.proto.type)
-            {
-                usesAuxSlot = true;
-                fieldValue = prototypeObject->GetAuxSlot(slotIndex);
-            }
-            else
-            {
-                fieldValue = prototypeObject->GetInlineSlot(slotIndex);
-            }
-            isMissing = localCache.u.proto.isMissing;
-            propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
-        }
-        else
-        {
-            slotIndex = localCache.u.accessor.slotIndex;
-            if (type != localCache.u.accessor.type)
-            {
-                usesAuxSlot = true;
-                fieldValue = localCache.u.accessor.object->GetAuxSlot(slotIndex);
-            }
-            else
-            {
-                fieldValue = localCache.u.accessor.object->GetInlineSlot(slotIndex);
-            }
-        }
-
-        // Keep the type alive until the entry point is installed. Note that this is longer than just during JIT, for which references
-        // from the JitTimeData would have been enough.
-        Assert(entryPoint->GetJitTransferData() != nullptr);
-        entryPoint->GetJitTransferData()->AddJitTimeTypeRef(type, recycler);
-
-        bool allFixedPhaseOFF = PHASE_OFF(Js::FixedMethodsPhase, topFunctionBody) & PHASE_OFF(Js::UseFixedDataPropsPhase, topFunctionBody);
-
-        if (!allFixedPhaseOFF)
-        {
-            Assert(propertyOwnerType != nullptr);
-            if (Js::DynamicType::Is(propertyOwnerType->GetTypeId()))
-            {
-                Js::DynamicTypeHandler* propertyOwnerTypeHandler = ((Js::DynamicType*)propertyOwnerType)->GetTypeHandler();
-                Js::PropertyRecord const * const fixedPropertyRecord = functionBody->GetScriptContext()->GetPropertyName(propertyId);
-                Var fixedProperty = nullptr;
-                Js::JavascriptFunction* functionObject = nullptr;
-
-                if (isLocal || isProto)
-                {
-                    if (typeWithoutProperty == nullptr)
-                    {
-                        // Since we don't know if this cache is used for LdMethodFld, we may fix up (use as fixed) too
-                        // aggressively here, if we load a function that we don't actually call.  This happens in the case
-                        // of constructors (e.g. Object.defineProperty or Object.create).
-                        // TODO (InlineCacheCleanup): if we don't zero some slot(s) in the inline cache, we could store a bit there
-                        // indicating if this cache is used by LdMethodFld, and only ask then. We could even store a bit in the cache
-                        // indicating that the value loaded is a fixed function (or at least may still be). That last bit could work
-                        // even if we zero inline caches, since we would always set it when populating the cache.
-                        propertyOwnerTypeHandler->TryUseFixedProperty(fixedPropertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedMethodProperty | Js::FixedPropertyKind::FixedDataProperty), scriptContext);
-                    }
-                }
-                else
-                {
-                    propertyOwnerTypeHandler->TryUseFixedAccessor(fixedPropertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedAccessorProperty), isGetter, scriptContext);
-                }
-
-                if (fixedProperty != nullptr && propertyGuard == nullptr)
-                {
-                    propertyGuard = entryPoint->RegisterSharedPropertyGuard(propertyId, scriptContext);
-                }
-
-                if (fixedProperty != nullptr && Js::JavascriptFunction::Is(fixedProperty))
-                {
-                    functionObject = (Js::JavascriptFunction *)fixedProperty;
-                    if (PHASE_VERBOSE_TRACE(Js::FixedMethodsPhase, functionBody))
-                    {
-                        char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                        char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-
-                        Js::DynamicObject* protoObject = isProto ? prototypeObject : nullptr;
-                        Output::Print(_u("FixedFields: function %s (%s) cloning cache with fixed method: %s (%s), function: 0x%p, body: 0x%p (cache id: %d, layout: %s, type: 0x%p, proto: 0x%p, proto type: 0x%p)\n"),
-                            functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer),
-                            fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionProxy() ?
-                            functionObject->GetFunctionInfo()->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
-                            cacheId, isProto ? _u("proto") : _u("local"), type, protoObject, protoObject != nullptr ? protoObject->GetType() : nullptr);
-                        Output::Flush();
-                    }
-
-                    if (PHASE_VERBOSE_TESTTRACE(Js::FixedMethodsPhase, functionBody))
-                    {
-                        char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                        char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-
-                        Output::Print(_u("FixedFields: function %s (%s) cloning cache with fixed method: %s (%s) (cache id: %d, layout: %s)\n"),
-                            functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionProxy() ?
-                            functionObject->GetFunctionInfo()->GetFunctionProxy()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
-                            cacheId, isProto ? _u("proto") : _u("local"));
-                        Output::Flush();
-                    }
-
-                    // We don't need to check for a singleton here. We checked that the singleton still existed
-                    // when we obtained the fixed field value inside TryUseFixedProperty. Since we don't need the
-                    // singleton instance later in this function, we don't care if the instance got collected.
-                    // We get the type handler from the propertyOwnerType, which we got from the cache. At runtime,
-                    // if the object is collected, it is by definition unreachable and thus the code in the function
-                    // we're about to emit cannot reach the object to try to access any of this object's properties.
-
-                    ConstructorCache* runtimeConstructorCache = functionObject->GetConstructorCache();
-                    if (runtimeConstructorCache->IsSetUpForJit() && runtimeConstructorCache->GetScriptContext() == scriptContext)
-                    {
-                        FunctionInfo* functionInfo = functionObject->GetFunctionInfo();
-                        Assert(functionInfo != nullptr);
-                        Assert((functionInfo->GetAttributes() & FunctionInfo::ErrorOnNew) == 0);
-
-                        Assert(!runtimeConstructorCache->IsDefault());
-
-                        if (runtimeConstructorCache->IsNormal())
-                        {
-                            Assert(runtimeConstructorCache->GetType()->GetIsShared());
-                            // If we populated the cache with initial type before calling the constructor, but then didn't end up updating the cache
-                            // after the constructor and shrinking (and locking) the inline slot capacity, we must lock it now.  In that case it is
-                            // also possible that the inline slot capacity was shrunk since we originally cached it, so we must update it also.
-#if DBG_DUMP
-                            if (!runtimeConstructorCache->GetType()->GetTypeHandler()->GetIsInlineSlotCapacityLocked())
-                            {
-                                if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
-                                {
-                                    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                                    char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-
-                                    Output::Print(_u("FixedNewObj: function %s (%s) ctor cache for %s (%s) about to be cloned has unlocked inline slot count: guard value = 0x%p, type = 0x%p, slots = %d, inline slots = %d\n"),
-                                        functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
-                                        functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"),
-                                        runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->GetType(),
-                                        runtimeConstructorCache->GetSlotCount(), runtimeConstructorCache->GetInlineSlotCount());
-                                    Output::Flush();
-                                }
-                            }
-#endif
-                            runtimeConstructorCache->GetType()->GetTypeHandler()->EnsureInlineSlotCapacityIsLocked();
-                            runtimeConstructorCache->UpdateInlineSlotCount();
-                        }
-
-                        // We must keep the runtime cache alive as long as this entry point exists and may try to dereference it.
-                        entryPoint->RegisterConstructorCache(runtimeConstructorCache, recycler);
-                        ctorCache = RecyclerNew(recycler, JITTimeConstructorCache, functionObject, runtimeConstructorCache);
-
-                        if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
-                        {
-                            char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                            char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-
-                            Output::Print(_u("FixedNewObj: function %s (%s) cloning ctor cache for %s (%s): guard value = 0x%p, type = 0x%p, slots = %d, inline slots = %d\n"),
-                                functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
-                                functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
-                                runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->IsNormal() ? runtimeConstructorCache->GetType() : nullptr,
-                                runtimeConstructorCache->GetSlotCount(), runtimeConstructorCache->GetInlineSlotCount());
-                            Output::Flush();
-                        }
-                    }
-                    else
-                    {
-                        if (!runtimeConstructorCache->IsDefault())
-                        {
-                            if (PHASE_TRACE(Js::FixedNewObjPhase, functionBody))
-                            {
-                                char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                                char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-
-                                Output::Print(_u("FixedNewObj: function %s (%s) skipping ctor cache for %s (%s), because %s (guard value = 0x%p, script context = %p).\n"),
-                                    functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer), fixedPropertyRecord->GetBuffer(), functionObject->GetFunctionInfo()->GetFunctionBody() ?
-                                    functionObject->GetFunctionInfo()->GetFunctionBody()->GetDebugNumberSet(debugStringBuffer2) : _u("(null)"), functionObject, functionObject->GetFunctionInfo(),
-                                    runtimeConstructorCache->IsEmpty() ? _u("cache is empty (or has been cleared)") :
-                                    runtimeConstructorCache->IsInvalidated() ? _u("cache is invalidated") :
-                                    runtimeConstructorCache->SkipDefaultNewObject() ? _u("default new object isn't needed") :
-                                    runtimeConstructorCache->NeedsTypeUpdate() ? _u("cache needs to be updated") :
-                                    runtimeConstructorCache->NeedsUpdateAfterCtor() ? _u("cache needs update after ctor") :
-                                    runtimeConstructorCache->IsPolymorphic() ? _u("cache is polymorphic") :
-                                    runtimeConstructorCache->GetScriptContext() != functionBody->GetScriptContext() ? _u("script context mismatch") : _u("of an unexpected situation"),
-                                    runtimeConstructorCache->GetRawGuardValue(), runtimeConstructorCache->GetScriptContext());
-                                Output::Flush();
-                            }
-                        }
-                    }
-
-                    isBuiltIn = Js::JavascriptLibrary::GetBuiltinFunctionForPropId(propertyId) != Js::BuiltinFunction::None;
-                }
-
-                if (fixedProperty != nullptr)
-                {
-                    Assert(fieldValue == nullptr || fieldValue == fixedProperty);
-                    fieldValue = fixedProperty;
-                    isFieldValueFixed = true;
-                    keepFieldValue = true;
-                }
-            }
-        }
-
-        FixedFieldInfo* fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, 1);
-
-        fixedFieldInfoArray[0].fieldValue = fieldValue;
-        fixedFieldInfoArray[0].type = type;
-        fixedFieldInfoArray[0].nextHasSameFixedField = false;
-
-        ObjTypeSpecFldInfo* info;
-
-        // If we stress equivalent object type spec, let's pretend that every inline cache was polymorphic and equivalent.
-        bool forcePoly = false;
-        if ((!PHASE_OFF(Js::EquivObjTypeSpecByDefaultPhase, topFunctionBody) ||
-            PHASE_STRESS(Js::EquivObjTypeSpecPhase, topFunctionBody))
-            && !PHASE_OFF(Js::EquivObjTypeSpecPhase, topFunctionBody))
-        {
-            Assert(topFunctionBody->HasDynamicProfileInfo());
-            auto profileData = topFunctionBody->GetAnyDynamicProfileInfo();
-            // We only support equivalent fixed fields on loads from prototype, and no equivalence on missing properties
-            forcePoly |= !profileData->IsEquivalentObjTypeSpecDisabled() && (!isFieldValueFixed || isProto) && !isMissing;
-        }
-
-        if (isFieldValueFixed)
-        {
-            // Fixed field checks allow us to assume a specific type ID, but the assumption is only
-            // valid if we lock the type. Otherwise, the type ID may change out from under us without
-            // evolving the type.
-            if (DynamicType::Is(type->GetTypeId()))
-            {
-                DynamicType *dynamicType = static_cast<DynamicType*>(type);
-                if (!dynamicType->GetIsLocked())
-                {
-                    dynamicType->LockType();
-                }
-            }
-        }
-
-        if (forcePoly)
-        {
-            uint16 typeCount = 1;
-            RecyclerJITTypeHolder* types = RecyclerNewArray(recycler, RecyclerJITTypeHolder, typeCount);
-            types[0].t = RecyclerNew(recycler, JITType);
-            JITType::BuildFromJsType(type, types[0].t);
-            EquivalentTypeSet* typeSet = RecyclerNew(recycler, EquivalentTypeSet, types, typeCount);
-
-            info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
-                id, type->GetTypeId(), typeWithoutProperty, typeSet, usesAuxSlot, isProto, isAccessor, isFieldValueFixed, keepFieldValue, false/*doesntHaveEquivalence*/, false, slotIndex, propertyId,
-                prototypeObject, propertyGuard, ctorCache, fixedFieldInfoArray, 1);
-
-            if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
-            {
-                const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
-                Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type set: 0x%p\n"),
-                    id, propertyRecord->GetBuffer(), propertyId, slotIndex, type);
-                Output::Flush();
-            }
-        }
-        else
-        {
-            info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
-                id, type->GetTypeId(), typeWithoutProperty, usesAuxSlot, isProto, isAccessor, isFieldValueFixed, keepFieldValue, isBuiltIn, slotIndex, propertyId,
-                prototypeObject, propertyGuard, ctorCache, fixedFieldInfoArray);
-
-            if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
-            {
-                const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
-                Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type: 0x%p\n"),
-                    id, propertyRecord->GetBuffer(), propertyId, slotIndex, type);
-                Output::Flush();
-            }
-        }
-
-        return info;
-    }
-
-    ObjTypeSpecFldInfo* ObjTypeSpecFldInfo::CreateFrom(uint id, PolymorphicInlineCache* cache, uint cacheId, EntryPointInfo *entryPoint,
-        FunctionBody* const topFunctionBody, FunctionBody *const functionBody, FieldAccessStatsPtr inlineCacheStats)
-    {
-
-#ifdef FIELD_ACCESS_STATS
-#define IncInlineCacheCount(counter) if (inlineCacheStats) { inlineCacheStats->counter++; }
-#else
-#define IncInlineCacheCount(counter)
-#endif
-
-        Assert(topFunctionBody->HasDynamicProfileInfo());
-        auto profileData = topFunctionBody->GetAnyDynamicProfileInfo();
-
-        bool gatherDataForInlining = cache->GetCloneForJitTimeUse() && functionBody->PolyInliningUsingFixedMethodsAllowedByConfigFlags(topFunctionBody);
-
-        if (PHASE_OFF(Js::EquivObjTypeSpecPhase, topFunctionBody) || profileData->IsEquivalentObjTypeSpecDisabled())
-        {
-            if (!gatherDataForInlining)
-            {
-                return nullptr;
-            }
-        }
-
-        Assert(cache->GetSize() < UINT16_MAX);
-        Js::InlineCache* inlineCaches = cache->GetInlineCaches();
-        Js::DynamicObject* prototypeObject = nullptr;
-        Js::DynamicObject* accessorOwnerObject = nullptr;
-        Js::TypeId typeId = TypeIds_Limit;
-        uint16 polyCacheSize = (uint16)cache->GetSize();
-        uint16 firstNonEmptyCacheIndex = UINT16_MAX;
-        uint16 slotIndex = 0;
-        bool areEquivalent = true;
-        bool usesAuxSlot = false;
-        bool isProto = false;
-        bool isAccessor = false;
-        bool isGetterAccessor = false;
-        bool isAccessorOnProto = false;
-
-        bool stress = PHASE_STRESS(Js::EquivObjTypeSpecPhase, topFunctionBody);
-        bool areStressEquivalent = stress;
-
-        uint16 typeCount = 0;
-        for (uint16 i = 0; (areEquivalent || stress || gatherDataForInlining) && i < polyCacheSize; i++)
-        {
-            InlineCache& inlineCache = inlineCaches[i];
-            if (inlineCache.IsEmpty()) continue;
-
-            if (firstNonEmptyCacheIndex == UINT16_MAX)
-            {
-                if (inlineCache.IsLocal())
-                {
-                    typeId = TypeWithoutAuxSlotTag(inlineCache.u.local.type)->GetTypeId();
-                    usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.local.type);
-                    slotIndex = inlineCache.u.local.slotIndex;
-                    // We don't support equivalent object type spec for adding properties.
-                    areEquivalent = inlineCache.u.local.typeWithoutProperty == nullptr;
-                    gatherDataForInlining = false;
-                }
-                // Missing properties cannot be treated as equivalent, because for objects with SDTH or DTH, we don't change the object's type
-                // when we add a property.  We also don't invalidate proto inline caches (and guards) unless the property being added exists on the proto chain.
-                // Missing properties by definition do not exist on the proto chain, so in the end we could have an EquivalentObjTypeSpec cache hit on a
-                // property that once was missing, but has since been added. (See OS Bugs 280582).
-                else if (inlineCache.IsProto() && !inlineCache.u.proto.isMissing)
-                {
-                    isProto = true;
-                    typeId = TypeWithoutAuxSlotTag(inlineCache.u.proto.type)->GetTypeId();
-                    usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.proto.type);
-                    slotIndex = inlineCache.u.proto.slotIndex;
-                    prototypeObject = inlineCache.u.proto.prototypeObject;
-                }
-                else
-                {
-                    if (!PHASE_OFF(Js::FixAccessorPropsPhase, functionBody))
-                    {
-                        isAccessor = true;
-                        isGetterAccessor = inlineCache.IsGetterAccessor();
-                        isAccessorOnProto = inlineCache.u.accessor.isOnProto;
-                        accessorOwnerObject = inlineCache.u.accessor.object;
-                        typeId = TypeWithoutAuxSlotTag(inlineCache.u.accessor.type)->GetTypeId();
-                        usesAuxSlot = TypeHasAuxSlotTag(inlineCache.u.accessor.type);
-                        slotIndex = inlineCache.u.accessor.slotIndex;
-                    }
-                    else
-                    {
-                        areEquivalent = false;
-                        areStressEquivalent = false;
-                    }
-                    gatherDataForInlining = false;
-                }
-
-                // If we're stressing equivalent object type spec then let's keep trying to find a cache that we could use.
-                if (!stress || areStressEquivalent)
-                {
-                    firstNonEmptyCacheIndex = i;
-                }
-            }
-            else
-            {
-                if (inlineCache.IsLocal())
-                {
-                    if (isProto || isAccessor || inlineCache.u.local.typeWithoutProperty != nullptr || slotIndex != inlineCache.u.local.slotIndex ||
-                        typeId != TypeWithoutAuxSlotTag(inlineCache.u.local.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.local.type))
-                    {
-                        areEquivalent = false;
-                    }
-                    gatherDataForInlining = false;
-                }
-                else if (inlineCache.IsProto())
-                {
-                    if (!isProto || isAccessor || prototypeObject != inlineCache.u.proto.prototypeObject || slotIndex != inlineCache.u.proto.slotIndex ||
-                        typeId != TypeWithoutAuxSlotTag(inlineCache.u.proto.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.proto.type))
-                    {
-                        areEquivalent = false;
-                    }
-                }
-                else
-                {
-                    // Supporting equivalent obj type spec only for those polymorphic accessor property operations for which
-                    // 1. the property is on the same prototype, and
-                    // 2. the types are equivalent.
-                    //
-                    // This is done to keep the equivalence check helper as-is
-                    if (!isAccessor || isGetterAccessor != inlineCache.IsGetterAccessor() || !isAccessorOnProto || !inlineCache.u.accessor.isOnProto || accessorOwnerObject != inlineCache.u.accessor.object ||
-                        slotIndex != inlineCache.u.accessor.slotIndex || typeId != TypeWithoutAuxSlotTag(inlineCache.u.accessor.type)->GetTypeId() || usesAuxSlot != TypeHasAuxSlotTag(inlineCache.u.accessor.type))
-                    {
-                        areEquivalent = false;
-                    }
-                    gatherDataForInlining = false;
-                }
-            }
-            typeCount++;
-        }
-
-        if (firstNonEmptyCacheIndex == UINT16_MAX)
-        {
-            IncInlineCacheCount(emptyPolyInlineCacheCount);
-            return nullptr;
-        }
-
-        if (cache->GetIgnoreForEquivalentObjTypeSpec())
-        {
-            areEquivalent = areStressEquivalent = false;
-        }
-
-        gatherDataForInlining = gatherDataForInlining && (typeCount <= 4); // Only support 4-way (max) polymorphic inlining
-        if (!areEquivalent && !areStressEquivalent)
-        {
-            IncInlineCacheCount(nonEquivPolyInlineCacheCount);
-            cache->SetIgnoreForEquivalentObjTypeSpec(true);
-            if (!gatherDataForInlining)
-            {
-                return nullptr;
-            }
-        }
-
-        Assert(firstNonEmptyCacheIndex < polyCacheSize);
-        Assert(typeId != TypeIds_Limit);
-        IncInlineCacheCount(equivPolyInlineCacheCount);
-
-        // If we're stressing equivalent object type spec and the types are not equivalent, let's grab the first one only.
-        if (stress && (areEquivalent != areStressEquivalent))
-        {
-            polyCacheSize = firstNonEmptyCacheIndex + 1;
-        }
-
-        ScriptContext* scriptContext = functionBody->GetScriptContext();
-        Recycler* recycler = scriptContext->GetRecycler();
-
-        uint16 fixedFunctionCount = 0;
-
-        // Need to create a local array here and not allocate one from the recycler,
-        // as the allocation may trigger a GC which can clear the inline caches.
-        FixedFieldInfo localFixedFieldInfoArray[Js::DynamicProfileInfo::maxPolymorphicInliningSize] = { };
-
-        // For polymorphic field loads we only support fixed functions on prototypes. This helps keep the equivalence check helper simple.
-        // Since all types in the polymorphic cache share the same prototype, it's enough to grab the fixed function from the prototype object.
-        Var fixedProperty = nullptr;
-        if ((isProto || isAccessorOnProto) && (areEquivalent || areStressEquivalent))
-        {
-            const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(cacheId));
-            if (isProto)
-            {
-                prototypeObject->GetDynamicType()->GetTypeHandler()->TryUseFixedProperty(propertyRecord, &fixedProperty, (Js::FixedPropertyKind)(Js::FixedPropertyKind::FixedMethodProperty | Js::FixedPropertyKind::FixedDataProperty), scriptContext);
-            }
-            else if (isAccessorOnProto)
-            {
-                accessorOwnerObject->GetDynamicType()->GetTypeHandler()->TryUseFixedAccessor(propertyRecord, &fixedProperty, Js::FixedPropertyKind::FixedAccessorProperty, isGetterAccessor, scriptContext);
-            }
-
-            localFixedFieldInfoArray[0].fieldValue = fixedProperty;
-            localFixedFieldInfoArray[0].type = nullptr;
-            localFixedFieldInfoArray[0].nextHasSameFixedField = false;
-
-            // TODO (ObjTypeSpec): Enable constructor caches on equivalent polymorphic field loads with fixed functions.
-        }
-
-        // Let's get the types.
-        Js::Type* localTypes[MaxPolymorphicInlineCacheSize];
-        uint16 typeNumber = 0;
-        Js::JavascriptFunction* fixedFunctionObject = nullptr;
-        for (uint16 i = firstNonEmptyCacheIndex; i < polyCacheSize; i++)
-        {
-            InlineCache& inlineCache = inlineCaches[i];
-            if (inlineCache.IsEmpty()) continue;
-
-            localTypes[typeNumber] = inlineCache.IsLocal() ? TypeWithoutAuxSlotTag(inlineCache.u.local.type) :
-                inlineCache.IsProto() ? TypeWithoutAuxSlotTag(inlineCache.u.proto.type) :
-                TypeWithoutAuxSlotTag(inlineCache.u.accessor.type);
-
-            if (gatherDataForInlining)
-            {
-                inlineCache.TryGetFixedMethodFromCache(functionBody, cacheId, &fixedFunctionObject);
-                if (!fixedFunctionObject || !fixedFunctionObject->GetFunctionInfo()->HasBody())
-                {
-                    if (!(areEquivalent || areStressEquivalent))
-                    {
-                        // If we reach here only because we are gathering data for inlining, and one of the Inline Caches doesn't have a fixedfunction object, return.
-                        return nullptr;
-                    }
-                    else
-                    {
-                        // If one of the inline caches doesn't have a fixed function object, abort gathering inlining data.
-                        gatherDataForInlining = false;
-                        typeNumber++;
-                        continue;
-                    }
-                }
-
-                // We got a fixed function object from the cache.
-
-                localFixedFieldInfoArray[typeNumber].type = localTypes[typeNumber];
-                localFixedFieldInfoArray[typeNumber].fieldValue = fixedFunctionObject;
-                localFixedFieldInfoArray[typeNumber].nextHasSameFixedField = false;
-                fixedFunctionCount++;
-            }
-
-            typeNumber++;
-        }
-
-        if (isAccessor && gatherDataForInlining)
-        {
-            Assert(fixedFunctionCount <= 1);
-        }
-
-        if (stress && (areEquivalent != areStressEquivalent))
-        {
-            typeCount = 1;
-        }
-
-        AnalysisAssert(typeNumber == typeCount);
-
-        // Now that we've copied all material info into local variables, we can start allocating without fear
-        // that a garbage collection will clear any of the live inline caches.
-
-        FixedFieldInfo* fixedFieldInfoArray;
-        if (gatherDataForInlining)
-        {
-            fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, fixedFunctionCount);
-            CopyArray<FixedFieldInfo, Field(Var)>(
-                fixedFieldInfoArray, fixedFunctionCount, localFixedFieldInfoArray, fixedFunctionCount);
-        }
-        else
-        {
-            fixedFieldInfoArray = RecyclerNewArrayZ(recycler, FixedFieldInfo, 1);
-            CopyArray<FixedFieldInfo, Field(Var)>(fixedFieldInfoArray, 1, localFixedFieldInfoArray, 1);
-        }
-
-        Js::PropertyId propertyId = functionBody->GetPropertyIdFromCacheId(cacheId);
-        Js::PropertyGuard* propertyGuard = entryPoint->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.
-        bool hasFixedValue = gatherDataForInlining ||
-            ((isProto || isAccessorOnProto) && (areEquivalent || areStressEquivalent) && localFixedFieldInfoArray[0].fieldValue);
-
-        bool doesntHaveEquivalence = !(areEquivalent || areStressEquivalent);
-
-        EquivalentTypeSet* typeSet = nullptr;
-        auto jitTransferData = entryPoint->GetJitTransferData();
-        Assert(jitTransferData != nullptr);
-        if (areEquivalent || areStressEquivalent)
-        {
-            RecyclerJITTypeHolder* types = RecyclerNewArray(recycler, RecyclerJITTypeHolder, typeCount);
-            for (uint16 i = 0; i < typeCount; i++)
-            {
-                jitTransferData->AddJitTimeTypeRef(localTypes[i], recycler);
-                if (hasFixedValue)
-                {
-                    // Fixed field checks allow us to assume a specific type ID, but the assumption is only
-                    // valid if we lock the type. Otherwise, the type ID may change out from under us without
-                    // evolving the type.
-                    if (DynamicType::Is(localTypes[i]->GetTypeId()))
-                    {
-                        DynamicType *dynamicType = static_cast<DynamicType*>(localTypes[i]);
-                        if (!dynamicType->GetIsLocked())
-                        {
-                            dynamicType->LockType();
-                        }
-                    }
-                }
-                // TODO: OOP JIT, consider putting these inline
-                types[i].t = RecyclerNew(recycler, JITType);
-                __analysis_assume(localTypes[i] != nullptr);
-                JITType::BuildFromJsType(localTypes[i], types[i].t);
-            }
-            typeSet = RecyclerNew(recycler, EquivalentTypeSet, types, typeCount);
-        }
-
-        ObjTypeSpecFldInfo* info = RecyclerNew(recycler, ObjTypeSpecFldInfo,
-            id, typeId, nullptr, typeSet, usesAuxSlot, isProto, isAccessor, hasFixedValue, hasFixedValue, doesntHaveEquivalence, true, slotIndex, propertyId,
-            prototypeObject, propertyGuard, nullptr, fixedFieldInfoArray, fixedFunctionCount/*, nullptr, nullptr, nullptr*/);
-
-        if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
-        {
-            if (PHASE_TRACE(Js::ObjTypeSpecPhase, topFunctionBody) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, topFunctionBody))
-            {
-                if (typeSet)
-                {
-                    const PropertyRecord* propertyRecord = scriptContext->GetPropertyName(propertyId);
-                    Output::Print(_u("Created ObjTypeSpecFldInfo: id %u, property %s(#%u), slot %u, type set: "),
-                        id, propertyRecord->GetBuffer(), propertyId, slotIndex);
-                    for (uint16 ti = 0; ti < typeCount - 1; ti++)
-                    {
-                        Output::Print(_u("0x%p, "), typeSet->GetType(ti));
-                    }
-                    Output::Print(_u("0x%p\n"), typeSet->GetType(typeCount - 1));
-                    Output::Flush();
-                }
-            }
-        }
-
-        return info;
-
-#undef IncInlineCacheCount
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFixedFunction() const
-    {
-        Assert(HasFixedValue());
-        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-        Assert(this->fixedFieldInfoArray[0].fieldValue != nullptr && Js::JavascriptFunction::Is(this->fixedFieldInfoArray[0].fieldValue));
-
-        return Js::JavascriptFunction::FromVar(this->fixedFieldInfoArray[0].fieldValue);
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFixedFunction(uint i) const
-    {
-        Assert(HasFixedValue());
-        Assert(IsPoly());
-        Assert(this->fixedFieldInfoArray[i].fieldValue != nullptr && Js::JavascriptFunction::Is(this->fixedFieldInfoArray[i].fieldValue));
-
-        return Js::JavascriptFunction::FromVar(this->fixedFieldInfoArray[i].fieldValue);
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFunction() const
-    {
-        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-        Assert(this->fixedFieldInfoArray[0].fieldValue != nullptr && JavascriptFunction::Is(this->fixedFieldInfoArray[0].fieldValue));
-
-        return JavascriptFunction::FromVar(this->fixedFieldInfoArray[0].fieldValue);
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFunctionIfAvailable() const
-    {
-        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-
-        if (PHASE_OFF1(ObjTypeSpecPhase)) return nullptr; // TODO: (lei)remove this after obj type spec for OOPJIT implemented
-
-        return this->fixedFieldInfoArray[0].fieldValue != nullptr && JavascriptFunction::Is(this->fixedFieldInfoArray[0].fieldValue) ?
-            JavascriptFunction::FromVar(this->fixedFieldInfoArray[0].fieldValue) : nullptr;
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFixedFunctionIfAvailable() const
-    {
-        Assert(HasFixedValue());
-        Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-        return GetFieldValueAsFunctionIfAvailable();
-    }
-
-    Js::JavascriptFunction* ObjTypeSpecFldInfo::GetFieldValueAsFixedFunctionIfAvailable(uint i) const
-    {
-        Assert(HasFixedValue());
-        Assert(IsPoly());
-        return this->fixedFieldInfoArray[i].fieldValue != nullptr && JavascriptFunction::Is(this->fixedFieldInfoArray[i].fieldValue) ?
-            JavascriptFunction::FromVar(this->fixedFieldInfoArray[i].fieldValue) : nullptr;
-    }
-
-    JITTypeHolder ObjTypeSpecFldInfo::GetFirstEquivalentType() const
-    {
-        Assert(IsObjTypeSpecCandidate() && this->typeSet);
-        return this->typeSet->GetFirstType();
-    }
-
-    Js::Var ObjTypeSpecFldInfo::GetFieldValueAsFixedDataIfAvailable() const
-    {
-        Assert(HasFixedValue() && this->fixedFieldCount == 1);
-
-        if (PHASE_OFF1(ObjTypeSpecPhase)) return nullptr; // TODO: (lei)remove this after obj type spec for OOPJIT implemented
-
-        return this->fixedFieldInfoArray[0].fieldValue;
-    }
-
-#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
-    const char16* ObjTypeSpecFldInfo::GetCacheLayoutString() const
-    {
-        return IsLoadedFromProto() ? _u("proto") : UsesAccessor() ? _u("flags") : _u("local");
-    }
-#endif
-
-    ObjTypeSpecFldInfoArray::ObjTypeSpecFldInfoArray()
-        : infoArray(nullptr)
-#if DBG
-        , infoCount(0)
-#endif
-    {
-    }
-
-    void ObjTypeSpecFldInfoArray::EnsureArray(Recycler *const recycler, FunctionBody *const functionBody)
-    {
-        Assert(recycler != nullptr);
-        Assert(functionBody != nullptr);
-        Assert(functionBody->GetInlineCacheCount() != 0);
-
-        if (this->infoArray)
-        {
-            Assert(functionBody->GetInlineCacheCount() == this->infoCount);
-            return;
-        }
-
-        this->infoArray = RecyclerNewArrayZ(recycler, Field(ObjTypeSpecFldInfo*), functionBody->GetInlineCacheCount());
-#if DBG
-        this->infoCount = functionBody->GetInlineCacheCount();
-#endif
-    }
-
-    ObjTypeSpecFldInfo* ObjTypeSpecFldInfoArray::GetInfo(FunctionBody *const functionBody, const uint index) const
-    {
-        Assert(functionBody);
-        Assert(this->infoArray == nullptr || functionBody->GetInlineCacheCount() == this->infoCount);
-        Assert(index < functionBody->GetInlineCacheCount());
-        return this->infoArray ? this->infoArray[index] : nullptr;
-    }
-
-    void ObjTypeSpecFldInfoArray::SetInfo(Recycler *const recycler, FunctionBody *const functionBody,
-        const uint index, ObjTypeSpecFldInfo* info)
-    {
-        Assert(recycler);
-        Assert(functionBody);
-        Assert(this->infoArray == nullptr || functionBody->GetInlineCacheCount() == this->infoCount);
-        Assert(index < functionBody->GetInlineCacheCount());
-        Assert(info);
-
-        EnsureArray(recycler, functionBody);
-        this->infoArray[index] = info;
-    }
-
-    void ObjTypeSpecFldInfoArray::Reset()
-    {
-        this->infoArray = nullptr;
-#if DBG
-        this->infoCount = 0;
-#endif
-    }
-}
-#endif // ENABLE_NATIVE_CODEGEN

+ 0 - 414
lib/Runtime/Language/ObjTypeSpecFldInfo.h

@@ -1,414 +0,0 @@
-//-------------------------------------------------------------------------------------------------------
-// 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
-
-// forward declaration
-class JITTimeConstructorCache;
-
-namespace Js
-{
-
-#define InitialObjTypeSpecFldInfoFlagValue 0x01
-
-    struct FixedFieldInfo
-    {
-        Field(Var) fieldValue;
-        Field(Type*) type;
-        Field(bool) nextHasSameFixedField; // set to true if the next entry in the FixedFieldInfo array on ObjTypeSpecFldInfo has the same type
-    };
-
-    // Union with uint16 flags for fast default initialization
-    union ObjTypeSpecFldInfoFlags
-    {
-        struct
-        {
-            Field(bool) falseReferencePreventionBit : 1;
-            Field(bool) isPolymorphic : 1;
-            Field(bool) isRootObjectNonConfigurableField : 1;
-            Field(bool) isRootObjectNonConfigurableFieldLoad : 1;
-            Field(bool) usesAuxSlot : 1;
-            Field(bool) isLocal : 1;
-            Field(bool) isLoadedFromProto : 1;
-            Field(bool) usesAccessor : 1;
-            Field(bool) hasFixedValue : 1;
-            Field(bool) keepFieldValue : 1;
-            Field(bool) isBeingStored : 1;
-            Field(bool) isBeingAdded : 1;
-            Field(bool) doesntHaveEquivalence : 1;
-            Field(bool) isBuiltIn : 1;
-        };
-        struct
-        {
-            Field(uint16) flags;
-        };
-        ObjTypeSpecFldInfoFlags(uint16 flags) : flags(flags) { }
-    };
-
-    class ObjTypeSpecFldInfo
-    {
-    private:
-        Field(DynamicObject*) protoObject;
-        Field(PropertyGuard*) propertyGuard;
-        Field(EquivalentTypeSet*) typeSet;
-        Field(Type*) initialType;
-        Field(JITTimeConstructorCache*) ctorCache;
-        Field(FixedFieldInfo*) fixedFieldInfoArray;
-
-        Field(PropertyId) propertyId;
-        Field(Js::TypeId) typeId;
-        Field(uint) id;
-
-        Field(ObjTypeSpecFldInfoFlags) flags;
-        Field(uint16) slotIndex;
-
-        Field(uint16) fixedFieldCount; // currently used only for fields that are functions
-
-    public:
-        ObjTypeSpecFldInfo() :
-            id(0), typeId(TypeIds_Limit), typeSet(nullptr), initialType(nullptr), flags(InitialObjTypeSpecFldInfoFlagValue),
-            slotIndex(Constants::NoSlot), propertyId(Constants::NoProperty), protoObject(nullptr), propertyGuard(nullptr),
-            ctorCache(nullptr), fixedFieldInfoArray(nullptr) {}
-
-        ObjTypeSpecFldInfo(uint id, TypeId typeId, Type* initialType,
-            bool usesAuxSlot, bool isLoadedFromProto, bool usesAccessor, bool isFieldValueFixed, bool keepFieldValue, bool isBuiltIn,
-            uint16 slotIndex, PropertyId propertyId, DynamicObject* protoObject, PropertyGuard* propertyGuard,
-            JITTimeConstructorCache* ctorCache, FixedFieldInfo* fixedFieldInfoArray) :
-            id(id), typeId(typeId), typeSet(nullptr), initialType(initialType), flags(InitialObjTypeSpecFldInfoFlagValue),
-            slotIndex(slotIndex), propertyId(propertyId), protoObject(protoObject), propertyGuard(propertyGuard),
-            ctorCache(ctorCache), fixedFieldInfoArray(fixedFieldInfoArray)
-        {
-            this->flags.isPolymorphic = false;
-            this->flags.usesAuxSlot = usesAuxSlot;
-            this->flags.isLocal = !isLoadedFromProto && !usesAccessor;
-            this->flags.isLoadedFromProto = isLoadedFromProto;
-            this->flags.usesAccessor = usesAccessor;
-            this->flags.hasFixedValue = isFieldValueFixed;
-            this->flags.keepFieldValue = keepFieldValue;
-            this->flags.isBeingAdded = initialType != nullptr;
-            this->flags.doesntHaveEquivalence = true; // doesn't mean anything for data from a monomorphic cache
-            this->flags.isBuiltIn = isBuiltIn;
-            this->fixedFieldCount = 1;
-        }
-
-        ObjTypeSpecFldInfo(uint id, TypeId typeId, Type* initialType, EquivalentTypeSet* typeSet,
-            bool usesAuxSlot, bool isLoadedFromProto, bool usesAccessor, bool isFieldValueFixed, bool keepFieldValue, bool doesntHaveEquivalence, bool isPolymorphic,
-            uint16 slotIndex, PropertyId propertyId, DynamicObject* protoObject, PropertyGuard* propertyGuard,
-            JITTimeConstructorCache* ctorCache, FixedFieldInfo* fixedFieldInfoArray, uint16 fixedFieldCount) :
-            id(id), typeId(typeId), typeSet(typeSet), initialType(initialType), flags(InitialObjTypeSpecFldInfoFlagValue),
-            slotIndex(slotIndex), propertyId(propertyId), protoObject(protoObject), propertyGuard(propertyGuard),
-            ctorCache(ctorCache), fixedFieldInfoArray(fixedFieldInfoArray)
-        {
-            this->flags.isPolymorphic = isPolymorphic;
-            this->flags.usesAuxSlot = usesAuxSlot;
-            this->flags.isLocal = !isLoadedFromProto && !usesAccessor;
-            this->flags.isLoadedFromProto = isLoadedFromProto;
-            this->flags.usesAccessor = usesAccessor;
-            this->flags.hasFixedValue = isFieldValueFixed;
-            this->flags.keepFieldValue = keepFieldValue;
-            this->flags.isBeingAdded = initialType != nullptr;
-            this->flags.doesntHaveEquivalence = doesntHaveEquivalence;
-            this->flags.isBuiltIn = false;
-            this->fixedFieldCount = fixedFieldCount;
-        }
-
-        static ObjTypeSpecFldInfo* CreateFrom(uint id, InlineCache* cache, uint cacheId,
-            EntryPointInfo *entryPoint, FunctionBody* const topFunctionBody, FunctionBody *const functionBody, FieldAccessStatsPtr inlineCacheStats);
-
-        static ObjTypeSpecFldInfo* CreateFrom(uint id, PolymorphicInlineCache* cache, uint cacheId,
-            EntryPointInfo *entryPoint, FunctionBody* const topFunctionBody, FunctionBody *const functionBody, FieldAccessStatsPtr inlineCacheStats);
-
-        uint GetObjTypeSpecFldId() const
-        {
-            return this->id;
-        }
-
-        bool IsMono() const
-        {
-            return !this->flags.isPolymorphic;
-        }
-
-        bool IsPoly() const
-        {
-            return this->flags.isPolymorphic;
-        }
-
-        bool UsesAuxSlot() const
-        {
-            return this->flags.usesAuxSlot;
-        }
-
-        bool IsBuiltin() const
-        {
-            return this->flags.isBuiltIn;
-        }
-
-        void SetUsesAuxSlot(bool value)
-        {
-            this->flags.usesAuxSlot = value;
-        }
-
-        bool IsLoadedFromProto() const
-        {
-            return this->flags.isLoadedFromProto;
-        }
-
-        bool IsLocal() const
-        {
-            return this->flags.isLocal;
-        }
-
-        bool UsesAccessor() const
-        {
-            return this->flags.usesAccessor;
-        }
-
-        bool HasFixedValue() const
-        {
-            return this->flags.hasFixedValue;
-        }
-
-        void SetHasFixedValue(bool value)
-        {
-            this->flags.hasFixedValue = value;
-        }
-
-        bool IsBeingStored() const
-        {
-            return this->flags.isBeingStored;
-        }
-
-        void SetIsBeingStored(bool value)
-        {
-            this->flags.isBeingStored = value;
-        }
-
-        bool IsBeingAdded() const
-        {
-            return this->flags.isBeingAdded;
-        }
-
-        bool IsRootObjectNonConfigurableField() const
-        {
-            return this->flags.isRootObjectNonConfigurableField;
-        }
-
-        bool IsRootObjectNonConfigurableFieldLoad() const
-        {
-            return this->flags.isRootObjectNonConfigurableField && this->flags.isRootObjectNonConfigurableFieldLoad;
-        }
-
-        void SetRootObjectNonConfigurableField(bool isLoad)
-        {
-            this->flags.isRootObjectNonConfigurableField = true;
-            this->flags.isRootObjectNonConfigurableFieldLoad = isLoad;
-        }
-
-        bool DoesntHaveEquivalence() const
-        {
-            return this->flags.doesntHaveEquivalence;
-        }
-
-        void ClearFlags()
-        {
-            this->flags = 0;
-        }
-
-        void SetFlags(uint16 flags)
-        {
-            this->flags = flags | 0x01;
-        }
-
-        uint16 GetFlags() const
-        {
-            return this->flags.flags;
-        }
-
-        uint16 GetSlotIndex() const
-        {
-            return this->slotIndex;
-        }
-
-        void SetSlotIndex(uint16 index)
-        {
-            this->slotIndex = index;
-        }
-
-        PropertyId GetPropertyId() const
-        {
-            return this->propertyId;
-        }
-
-        Js::DynamicObject* GetProtoObject() const
-        {
-            Assert(IsLoadedFromProto());
-            return this->protoObject;
-        }
-
-        Var GetFieldValue() const
-        {
-            Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-            return this->fixedFieldInfoArray[0].fieldValue;
-        }
-
-        Var GetFieldValue(uint i) const
-        {
-            Assert(IsPoly());
-            return this->fixedFieldInfoArray[i].fieldValue;
-        }
-
-        void SetFieldValue(Var value)
-        {
-            Assert(IsMono() || (IsPoly() && !DoesntHaveEquivalence()));
-            this->fixedFieldInfoArray[0].fieldValue = value;
-        }
-
-        Var GetFieldValueAsFixedDataIfAvailable() const;
-
-        Js::JavascriptFunction* GetFieldValueAsFixedFunction() const;
-        Js::JavascriptFunction* GetFieldValueAsFixedFunction(uint i) const;
-
-        Js::JavascriptFunction* GetFieldValueAsFunction() const;
-
-        Js::JavascriptFunction* GetFieldValueAsFunctionIfAvailable() const;
-
-        Js::JavascriptFunction* GetFieldValueAsFixedFunctionIfAvailable() const;
-        Js::JavascriptFunction* GetFieldValueAsFixedFunctionIfAvailable(uint i) const;
-
-        bool GetKeepFieldValue() const
-        {
-            return this->flags.keepFieldValue;
-        }
-
-        JITTimeConstructorCache* GetCtorCache() const
-        {
-            return this->ctorCache;
-        }
-
-        Js::PropertyGuard* GetPropertyGuard() const
-        {
-            return this->propertyGuard;
-        }
-
-        bool IsObjTypeSpecCandidate() const
-        {
-            return true;
-        }
-
-        bool IsMonoObjTypeSpecCandidate() const
-        {
-            return IsObjTypeSpecCandidate() && IsMono();
-        }
-
-        bool IsPolyObjTypeSpecCandidate() const
-        {
-            return IsObjTypeSpecCandidate() && IsPoly();
-        }
-
-        Js::TypeId GetTypeId() const
-        {
-            Assert(typeId != TypeIds_Limit);
-            return this->typeId;
-        }
-
-        Js::TypeId GetTypeId(uint i) const
-        {
-            Assert(IsPoly());
-            return this->fixedFieldInfoArray[i].type->GetTypeId();
-        }
-
-        Js::Type * GetType() const
-        {
-            Assert(IsObjTypeSpecCandidate() && IsMono());
-            return this->fixedFieldInfoArray[0].type;
-        }
-
-        Js::Type * GetType(uint i) const
-        {
-            Assert(IsPoly());
-            return this->fixedFieldInfoArray[i].type;
-        }
-
-        bool HasInitialType() const
-        {
-            return IsObjTypeSpecCandidate() && IsMono() && !IsLoadedFromProto() && this->initialType != nullptr;
-        }
-
-        Js::Type * GetInitialType() const
-        {
-            Assert(IsObjTypeSpecCandidate() && IsMono() && !IsLoadedFromProto());
-            return this->initialType;
-        }
-
-        Js::EquivalentTypeSet * GetEquivalentTypeSet() const
-        {
-            Assert(IsObjTypeSpecCandidate());
-            return this->typeSet;
-        }
-
-        JITTypeHolder GetFirstEquivalentType() const;
-
-        Js::FixedFieldInfo* GetFixedFieldInfoArray()
-        {
-            return this->fixedFieldInfoArray;
-        }
-
-        uint16 GetFixedFieldCount() const
-        {
-            return this->fixedFieldCount;
-        }
-
-#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
-        const char16 *GetCacheLayoutString() const;
-#endif
-    };
-
-    class ObjTypeSpecFldInfoArray
-    {
-    private:
-        Field(Field(ObjTypeSpecFldInfo*)*) infoArray;
-#if DBG
-        Field(uint) infoCount;
-#endif
-    public:
-        ObjTypeSpecFldInfoArray();
-
-    private:
-        void EnsureArray(Recycler *const recycler, FunctionBody *const functionBody);
-
-    public:
-        ObjTypeSpecFldInfo* GetInfo(FunctionBody *const functionBody, const uint index) const;
-        ObjTypeSpecFldInfo* GetInfo(const uint index) const;
-        Field(ObjTypeSpecFldInfo*)* GetInfoArray() const { return infoArray; }
-
-        void SetInfo(Recycler *const recycler, FunctionBody *const functionBody,
-            const uint index, ObjTypeSpecFldInfo* info);
-
-        void Reset();
-
-        template <class Fn>
-        void Map(Fn fn, uint count) const
-        {
-            if (this->infoArray != nullptr)
-            {
-                for (uint i = 0; i < count; i++)
-                {
-                    ObjTypeSpecFldInfo* info = this->infoArray[i];
-
-                    if (info != nullptr)
-                    {
-                        fn(info);
-                    }
-                }
-            }
-        };
-
-        PREVENT_COPY(ObjTypeSpecFldInfoArray)
-    };
-}
-#endif // ENABLE_NATIVE_CODEGEN
-

+ 0 - 2
lib/Runtime/Language/RuntimeLanguagePch.h

@@ -19,8 +19,6 @@
 #include "Language/AsmJsEncoder.h"
 #include "Language/AsmJsCodeGenerator.h"
 #endif
-#include "Language/ObjTypeSpecFldInfo.h"
-#include "Language/FunctionCodeGenJitTimeData.h"
 
 #include "Language/ProfilingHelpers.h"
 #include "Language/CacheOperators.h"