[MERGE #6091 @meg-gupta] OS#20500679: Disable addition of masking blocks for speculation hoisting when globopt is off

Merge pull request #6091 from meg-gupta:fixspechoist

Addition of masking on blocks for speculation hoisting on loop out edges was turned off for SimpleJit due to reduced perf concerns and issues with assigning regions.
However, it was not turned off when globopt is turned off. So we ended up with asserts regarding regions in FlowGraph::Destroy.
This changes fixes this.
diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp
index 62bbcef..d5a28f0 100644
--- a/lib/Backend/GlobOpt.cpp
+++ b/lib/Backend/GlobOpt.cpp
@@ -3286,10 +3286,14 @@
         }
         originalPropertySym = sym->AsPropertySym();
 
-        // Dont give a value to 'arguments' property sym to prevent field copy prop of 'arguments'
+        // Don't give a value to 'arguments' property sym to prevent field copy prop of 'arguments'
         if (originalPropertySym->AsPropertySym()->m_propertyId == Js::PropertyIds::arguments &&
             originalPropertySym->AsPropertySym()->m_fieldKind == PropertyKindData)
         {
+            if (opnd->AsSymOpnd()->IsPropertySymOpnd())
+            {
+                this->FinishOptPropOp(instr, opnd->AsPropertySymOpnd());
+            }
             return nullptr;
         }
 
@@ -4841,7 +4845,7 @@
         }
         else
         {
-            return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber(), dst);
+            return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber().SetCanBeTaggedValue(true), dst);
         }
         break;
 
@@ -4902,7 +4906,7 @@
         {
             valueType = ValueType::Number;
         }
-        return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);
+        return CreateDstUntransferredValue(valueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
     }
 
     case Js::OpCode::Add_A:
@@ -4936,12 +4940,12 @@
                     {
                         // If one of them is a float, the result probably is a float instead of just int
                         // but should always be a number.
-                        valueType = ValueType::Float;
+                        valueType = ValueType::Float.SetCanBeTaggedValue(true);
                     }
                     else
                     {
                         // Could be int, could be number
-                        valueType = ValueType::Number;
+                        valueType = ValueType::Number.SetCanBeTaggedValue(true);
                     }
                 }
                 else if (src1ValueInfo->IsLikelyFloat() || src2ValueInfo->IsLikelyFloat())
@@ -4965,7 +4969,7 @@
             && (src2Val && src2ValueInfo->IsNotString() && src2ValueInfo->IsPrimitive()))
         {
             // If src1 and src2 are not strings and primitive, add should yield a number.
-            valueType = ValueType::Number;
+            valueType = ValueType::Number.SetCanBeTaggedValue(true);
         }
         else if((src1Val && src1ValueInfo->IsLikelyString()) || (src2Val && src2ValueInfo->IsLikelyString()))
         {
@@ -4986,7 +4990,7 @@
             ValueType divValueType = GetDivValueType(instr, src1Val, src2Val, false);
             if (divValueType.IsLikelyInt() || divValueType.IsFloat())
             {
-                return CreateDstUntransferredValue(divValueType, instr, src1Val, src2Val);
+                return CreateDstUntransferredValue(divValueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
             }
         }
         // fall-through
@@ -5018,11 +5022,11 @@
             // This should ideally be NewNumberAndLikelyFloatValue since we know the result is a number but not sure if it will
             // be a float value. However, that Number/LikelyFloat value type doesn't exist currently and all the necessary
             // checks are done for float values (tagged int checks, etc.) so it's sufficient to just create a float value here.
-            valueType = ValueType::Float;
+            valueType = ValueType::Float.SetCanBeTaggedValue(true);
         }
         else
         {
-            valueType = ValueType::Number;
+            valueType = ValueType::Number.SetCanBeTaggedValue(true);
         }
 
         return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);
diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp
index ca37e7b..9523e49 100644
--- a/lib/Backend/GlobOptFields.cpp
+++ b/lib/Backend/GlobOptFields.cpp
@@ -229,10 +229,17 @@
         this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
         SetAnyPropertyMayBeWrittenTo();
     }
-    else if (inGlobOpt && indexOpnd && !indexOpnd->GetValueType().IsInt() && !currentBlock->globOptData.IsInt32TypeSpecialized(indexOpnd->m_sym))
+    else if (inGlobOpt)
     {
-        // Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
-        this->KillAllObjectTypes(bv);
+        Value * indexValue = indexOpnd ? this->currentBlock->globOptData.FindValue(indexOpnd->GetSym()) : nullptr;
+        ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
+        int indexLowerBound = 0;
+
+        if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
+        {
+            // Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
+            this->KillAllObjectTypes(bv);
+        }
     }
 }
 
@@ -479,7 +486,9 @@
     case Js::OpCode::NewScObjectNoCtor:
         if (inGlobOpt)
         {
-            KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
+            // Opcodes that make an object into a prototype may break object-header-inlining and final type opt.
+            // Kill all known object layouts.
+            KillAllObjectTypes(bv);
         }
         break;
 
diff --git a/lib/Backend/JITType.cpp b/lib/Backend/JITType.cpp
index a207dc5..a235bd0 100644
--- a/lib/Backend/JITType.cpp
+++ b/lib/Backend/JITType.cpp
@@ -35,7 +35,7 @@
 
         Js::DynamicTypeHandler * handler = dynamicType->GetTypeHandler();
         data->handler.isObjectHeaderInlinedTypeHandler = handler->IsObjectHeaderInlinedTypeHandler();
-        data->handler.isLocked = handler->GetIsLocked();
+        data->handler.flags = handler->GetFlags();
         data->handler.inlineSlotCapacity = handler->GetInlineSlotCapacity();
         data->handler.offsetOfInlineSlots = handler->GetOffsetOfInlineSlots();
         data->handler.slotCapacity = handler->GetSlotCapacity();
diff --git a/lib/Backend/JITTypeHandler.cpp b/lib/Backend/JITTypeHandler.cpp
index aca726b..dbecfb9 100644
--- a/lib/Backend/JITTypeHandler.cpp
+++ b/lib/Backend/JITTypeHandler.cpp
@@ -19,7 +19,13 @@
 bool
 JITTypeHandler::IsLocked() const
 {
-    return m_data.isLocked != FALSE;
+    return Js::DynamicTypeHandler::GetIsLocked(m_data.flags);
+}
+
+bool
+JITTypeHandler::IsPrototype() const
+{
+    return Js::DynamicTypeHandler::GetIsPrototype(m_data.flags);
 }
 
 uint16
diff --git a/lib/Backend/JITTypeHandler.h b/lib/Backend/JITTypeHandler.h
index c6e909f..9d2cc35 100644
--- a/lib/Backend/JITTypeHandler.h
+++ b/lib/Backend/JITTypeHandler.h
@@ -12,6 +12,7 @@
 
     bool IsObjectHeaderInlinedTypeHandler() const;
     bool IsLocked() const;
+    bool IsPrototype() const;
 
     uint16 GetInlineSlotCapacity() const;
     uint16 GetOffsetOfInlineSlots() const;
diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp
index 5d309c5..95f9e6b 100644
--- a/lib/Backend/Lower.cpp
+++ b/lib/Backend/Lower.cpp
@@ -6208,7 +6208,7 @@
 
     // Load the value from the slot, getting the slot ID from the cache.
     uint16 index = propertySymOpnd->GetSlotIndex();
-    Assert(index != -1);
+    AssertOrFailFast(index != (uint16)-1);
 
     if (opndSlotArray->IsRegOpnd())
     {
@@ -7247,7 +7247,7 @@
 
     // Store the value to the slot, getting the slot index from the cache.
     uint16 index = propertySymOpnd->GetSlotIndex();
-    Assert(index != -1);
+    AssertOrFailFast(index != (uint16)-1);
 
 #if defined(RECYCLER_WRITE_BARRIER_JIT) && (defined(_M_IX86) || defined(_M_AMD64))
     if (opndSlotArray->IsRegOpnd())
@@ -7399,6 +7399,19 @@
             !instrStFld->HasBailOutInfo() || instrStFld->OnlyHasLazyBailOut(),
             "Why does a direct field store have bailout that is not lazy?"
         );
+
+        if (propertySymOpnd->HasInitialType() && propertySymOpnd->HasFinalType())
+        {
+            bool isPrototypeTypeHandler = propertySymOpnd->GetInitialType()->GetTypeHandler()->IsPrototype();
+            if (isPrototypeTypeHandler)
+            {
+                LoadScriptContext(instrStFld);
+                m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
+                IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
+                instrStFld->InsertBefore(invalidateCallInstr);
+                m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
+            }
+        }
         instrStFld->Remove();
         return true;
     }
@@ -8215,6 +8228,16 @@
 
     // Now do the store.
     GenerateDirectFieldStore(instrStFld, propertySymOpnd);
+
+    bool isPrototypeTypeHandler = initialType->GetTypeHandler()->IsPrototype();
+    if (isPrototypeTypeHandler)
+    {
+        LoadScriptContext(instrStFld);
+        m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
+        IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
+        instrStFld->InsertBefore(invalidateCallInstr);
+        m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
+    }
 }
 
 bool
diff --git a/lib/Backend/SwitchIRBuilder.cpp b/lib/Backend/SwitchIRBuilder.cpp
index dd1034c..b44b887 100644
--- a/lib/Backend/SwitchIRBuilder.cpp
+++ b/lib/Backend/SwitchIRBuilder.cpp
@@ -163,7 +163,7 @@
 void
 SwitchIRBuilder::EndSwitch(uint32 offset, uint32 targetOffset)
 {
-    FlushCases(targetOffset);
+    FlushCases(offset);
     AssertMsg(m_caseNodes->Count() == 0, "Not all switch case nodes built by end of switch");
 
     // only generate the final unconditional jump at the end of the switch
diff --git a/lib/Common/Common/NumberUtilities.inl b/lib/Common/Common/NumberUtilities.inl
index 4783878..0a93593 100644
--- a/lib/Common/Common/NumberUtilities.inl
+++ b/lib/Common/Common/NumberUtilities.inl
@@ -7,6 +7,13 @@
 #define NUMBER_UTIL_INLINE
 #endif
 
+// Attempt to pun int/float without address-taking.
+// This helps compilers.
+
+#if defined(_AMD64_) || _M_IX86_FP >= 2 || defined(__AVX__)
+#include <immintrin.h>
+#endif
+
 #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
 #if defined(_MSC_VER) // WINDOWS
 
@@ -136,16 +143,18 @@
 
     NUMBER_UTIL_INLINE bool NumberUtilities::IsNan(double value)
     {
+        const uint64 nCompare = ToSpecial(value);
 #if defined(TARGET_64)
         // NaN is a range of values; all bits on the exponent are 1's 
         // and some nonzero significant. No distinction on signed NaN's.
-        uint64 nCompare = ToSpecial(value);
-        bool isNan = (0 == (~nCompare & 0x7FF0000000000000ull) &&
+        const bool isNan = (0 == (~nCompare & 0x7FF0000000000000ull) &&
             0 != (nCompare & 0x000FFFFFFFFFFFFFull));
         return isNan;
 #else
-        return 0 == (~Js::NumberUtilities::LuHiDbl(value) & 0x7FF00000) &&
-            (0 != Js::NumberUtilities::LuLoDbl(value) || 0 != (Js::NumberUtilities::LuHiDbl(value) & 0x000FFFFF));
+        const uint32 hi = (uint32)(nCompare >> 32);
+        const uint32 lo = (uint32)nCompare;
+        return 0 == (~hi & 0x7FF00000) &&
+            (0 != lo || 0 != (hi & 0x000FFFFF));
 #endif
     }
 
@@ -165,22 +174,46 @@
 
     NUMBER_UTIL_INLINE uint64 NumberUtilities::ToSpecial(double value)
     {
+#if defined(_AMD64_)
+        return _mm_cvtsi128_si64(_mm_castpd_si128(_mm_set_sd(value)));
+#elif defined(_M_ARM32_OR_ARM64)
+        return _CopyInt64FromDouble(value);
+#else
         return  *(reinterpret_cast<uint64 *>(&value));
+#endif
     }
 
     NUMBER_UTIL_INLINE uint32 NumberUtilities::ToSpecial(float value)
     {
+#if defined(_AMD64_) || _M_IX86_FP >= 2 || defined(__AVX__)
+        return _mm_cvtsi128_si32(_mm_castps_si128(_mm_set_ss(value)));
+#elif defined(_M_ARM32_OR_ARM64)
+        return _CopyInt32FromFloat(value);
+#else
         return  *(reinterpret_cast<uint32 *>(&value));
+#endif
     }
 
     NUMBER_UTIL_INLINE float NumberUtilities::ReinterpretBits(int value)
     {
+#if defined(_AMD64_) || _M_IX86_FP >= 2 || defined(__AVX__)
+        return _mm_cvtss_f32(_mm_castsi128_ps(_mm_cvtsi32_si128(value)));
+#elif defined(_M_ARM32_OR_ARM64)
+        return _CopyFloatFromInt32(value);
+#else
         return  *(reinterpret_cast<float *>(&value));
+#endif
     }
 
     NUMBER_UTIL_INLINE double NumberUtilities::ReinterpretBits(int64 value)
     {
+#if defined(_AMD64_)
+        return _mm_cvtsd_f64(_mm_castsi128_pd(_mm_cvtsi64_si128(value)));
+#elif defined(_M_ARM32_OR_ARM64)
+        return _CopyDoubleFromInt64(value);
+#else
         return  *(reinterpret_cast<double *>(&value));
+#endif
     }
 
     NUMBER_UTIL_INLINE bool NumberUtilities::IsFloat32NegZero(float value)
diff --git a/lib/JITIDL/JITTypes.h b/lib/JITIDL/JITTypes.h
index ae2f63b..ee057f1 100644
--- a/lib/JITIDL/JITTypes.h
+++ b/lib/JITIDL/JITTypes.h
@@ -90,7 +90,7 @@
 typedef struct TypeHandlerIDL
 {
     IDL_Field(boolean) isObjectHeaderInlinedTypeHandler;
-    IDL_Field(boolean) isLocked;
+    IDL_Field(unsigned char) flags;
 
     IDL_Field(unsigned short) inlineSlotCapacity;
     IDL_Field(unsigned short) offsetOfInlineSlots;
diff --git a/lib/Parser/Parse.cpp b/lib/Parser/Parse.cpp
index 5c0e1a8..e9241f8 100644
--- a/lib/Parser/Parse.cpp
+++ b/lib/Parser/Parse.cpp
@@ -11442,14 +11442,25 @@
 
 void Parser::FinishDeferredFunction(ParseNodeBlock * pnodeScopeList)
 {
-    uint saveNextBlockId = m_nextBlockId;
+    ParseContext parseContext;
+    this->CaptureContext(&parseContext);
+
     m_nextBlockId = pnodeScopeList->blockId + 1;
 
     FinishFunctionsInScope(pnodeScopeList,
-        [this](ParseNodeFnc * pnodeFnc)
+        [this, &parseContext](ParseNodeFnc * pnodeFnc)
     {
         Assert(pnodeFnc->nop == knopFncDecl);
 
+        // We need to scan this function based on the already known limits of the function declaration as some of
+        // the state such as fAllowIn may not be available at this point. Some of this state depends on the context
+        // of the function declaration. For example, a function declaration may be inside a for..in statement's var
+        // declaration. It may not be appropriate/possible to try and save all such context information. Functions
+        // that actually get deferred achieve this by going through the ParseSourceWithOffset code path.
+        this->GetScanner()->Clear();
+        this->GetScanner()->SetText(parseContext.pszSrc, pnodeFnc->cbMin /*+ this->m_scan.m_cMinTokMultiUnits*/, pnodeFnc->LengthInBytes(), pnodeFnc->ichMin, parseContext.isUtf8, parseContext.grfscr, pnodeFnc->lineNumber);
+        this->GetScanner()->Scan();
+
         // Non-simple params (such as default) require a good amount of logic to put vars on appropriate scopes. ParseFncDecl handles it
         // properly (both on defer and non-defer case). This is to avoid write duplicated logic here as well. Function with non-simple-param
         // will remain deferred until they are called.
@@ -11601,7 +11612,7 @@
         }
     });
 
-    m_nextBlockId = saveNextBlockId;
+    this->RestoreContext(&parseContext);
 }
 
 void Parser::InitPids()
diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp
index 407ecc4..b7b6abb 100644
--- a/lib/Runtime/Language/JavascriptOperators.cpp
+++ b/lib/Runtime/Language/JavascriptOperators.cpp
@@ -9849,6 +9849,11 @@
 
             Var result = CALL_ENTRYPOINT(threadContext, marshalledFunction->GetEntryPoint(), function, CallInfo(flags, 2), thisVar, putValue);
             Assert(result);
+
+            // Set implicit call flags so we bail out if we're trying to propagate the stored value forward. We can't count on the getter/setter
+            // to produce the stored value on a LdFld.
+            threadContext->AddImplicitCallFlags(ImplicitCall_Accessor);
+
             return nullptr;
         });
     }
diff --git a/lib/Runtime/Library/JavascriptArray.cpp b/lib/Runtime/Library/JavascriptArray.cpp
index fd020f0..6d0578b 100644
--- a/lib/Runtime/Library/JavascriptArray.cpp
+++ b/lib/Runtime/Library/JavascriptArray.cpp
@@ -9292,7 +9292,7 @@
                 }
                 else
                 {
-                    JavascriptOperators::OP_DeleteElementI(obj, JavascriptNumber::ToVar(toVal, scriptContext), scriptContext, PropertyOperation_ThrowOnDeleteIfNotConfig);
+                    JS_REENTRANT(jsReentLock, JavascriptOperators::OP_DeleteElementI(obj, JavascriptNumber::ToVar(toVal, scriptContext), scriptContext, PropertyOperation_ThrowOnDeleteIfNotConfig));
                 }
 
                 fromVal += direction;
@@ -11919,13 +11919,12 @@
 
         if (IsInlineSegment(src, instance))
         {
-            Assert(src->size <= SparseArraySegmentBase::INLINE_CHUNK_SIZE);
-
             // Copy head segment data between inlined head segments
             dst = DetermineInlineHeadSegmentPointer<T, 0, true>(static_cast<T*>(this));
             dst->left = src->left;
             dst->length = src->length;
-            dst->size = src->size;
+            uint inlineChunkSize = SparseArraySegmentBase::INLINE_CHUNK_SIZE;
+            dst->size = min(src->size, inlineChunkSize);
         }
         else
         {
@@ -11940,7 +11939,8 @@
 
         Assert(IsInlineSegment(src, instance) == IsInlineSegment(dst, static_cast<T*>(this)));
 
-        CopyArray(dst->elements, dst->size, src->elements, src->size);
+        AssertOrFailFast(dst->size <= src->size);
+        CopyArray(dst->elements, dst->size, src->elements, dst->size);
 
         if (!deepCopy)
         {
diff --git a/lib/Runtime/Library/JavascriptNumber.inl b/lib/Runtime/Library/JavascriptNumber.inl
index 3c8b661..e18c5f7 100644
--- a/lib/Runtime/Library/JavascriptNumber.inl
+++ b/lib/Runtime/Library/JavascriptNumber.inl
@@ -147,7 +147,7 @@
 
     inline Var JavascriptNumber::ToVar(double value)
     {
-        uint64 val = *(uint64*)&value;
+        const uint64 val = ToSpecial(value);
         AssertMsg(!IsNan(value) || ToSpecial(value) == k_NegativeNan || ToSpecial(value) == 0x7FF8000000000000ull, "We should only produce a NaN with this value");
         return reinterpret_cast<Var>(val ^ FloatTag_Value);
     }
diff --git a/lib/Runtime/Library/JavascriptRegExpConstructor.cpp b/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
index e1d347b..2be4848 100644
--- a/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
+++ b/lib/Runtime/Library/JavascriptRegExpConstructor.cpp
@@ -360,6 +360,10 @@
                 EnsureValues(); // The last match info relies on the last input. Use it before it is changed.
                 this->lastInput = tempInput;
             }
+
+            // Set implicit call flags since we are not necessarily making the original stored value available on re-load
+            // and are killing the store that backs two exposed properties.
+            this->GetScriptContext()->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
             *result = true;
             return true;
         case PropertyIds::lastMatch:
diff --git a/lib/Runtime/Library/ScriptFunction.cpp b/lib/Runtime/Library/ScriptFunction.cpp
index d6fd1c2..8e57b05 100644
--- a/lib/Runtime/Library/ScriptFunction.cpp
+++ b/lib/Runtime/Library/ScriptFunction.cpp
@@ -119,6 +119,16 @@
         ScriptFunction* scriptFunc = ScriptFunction::OP_NewScFunc(environment, infoRef);
         scriptFunc->SetHomeObj(homeObj);
 
+        // After setting homeobject we need to set the name if the object is ready.
+        if ((*infoRef)->GetFunctionProxy()->GetUndeferredFunctionType())
+        {
+            if (!scriptFunc->IsAnonymousFunction() && !scriptFunc->GetFunctionProxy()->EnsureDeserialized()->GetIsStaticNameFunction())
+            {
+                JavascriptString * functionName = scriptFunc->GetDisplayNameImpl();
+                scriptFunc->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr);
+            }
+        }
+
         return scriptFunc;
         JIT_HELPER_END(ScrFunc_OP_NewScFuncHomeObj);
     }
diff --git a/lib/Runtime/Math/WasmMath.inl b/lib/Runtime/Math/WasmMath.inl
index 483c7b5..09c1f29 100644
--- a/lib/Runtime/Math/WasmMath.inl
+++ b/lib/Runtime/Math/WasmMath.inl
@@ -155,6 +155,8 @@
         return 0;
     }
 
+    // TODO NumberUtilities::ToSpecial
+
     ReinterpretType val = *reinterpret_cast<ReinterpretType*> (&srcVal);
     if (MaxCmp(val, Max) || (val >= NegZero && NegOneCmp(val, NegOne)))
     {
diff --git a/lib/Runtime/Types/DictionaryTypeHandler.cpp b/lib/Runtime/Types/DictionaryTypeHandler.cpp
index 23f383e..2308eba 100644
--- a/lib/Runtime/Types/DictionaryTypeHandler.cpp
+++ b/lib/Runtime/Types/DictionaryTypeHandler.cpp
@@ -139,7 +139,7 @@
                 PropertyString* propertyString = scriptContext->GetPropertyString(*propertyId);
                 *propertyStringName = propertyString;
                 T dataSlot = descriptor.template GetDataPropertyIndex<false>();
-                if (dataSlot != NoSlots && (attribs & PropertyWritable))
+                if (dataSlot != NoSlots && (attribs & PropertyWritable) && type == typeToEnumerate)
                 {
                     PropertyValueInfo::SetCacheInfo(info, propertyString, propertyString->GetLdElemInlineCache(), false);
                     SetPropertyValueInfo(info, instance, dataSlot, &descriptor);
diff --git a/lib/Runtime/Types/SimpleTypeHandler.cpp b/lib/Runtime/Types/SimpleTypeHandler.cpp
index d71416b..8de4ea8 100644
--- a/lib/Runtime/Types/SimpleTypeHandler.cpp
+++ b/lib/Runtime/Types/SimpleTypeHandler.cpp
@@ -326,7 +326,7 @@
                 *propertyStringName = propStr;
 
                 PropertyValueInfo::SetCacheInfo(info, propStr, propStr->GetLdElemInlineCache(), false);
-                if ((attribs & PropertyWritable) == PropertyWritable)
+                if ((attribs & PropertyWritable) == PropertyWritable && type == typeToEnumerate)
                 {
                     PropertyValueInfo::Set(info, instance, index, attribs);
                 }
diff --git a/lib/Runtime/Types/TypeHandler.h b/lib/Runtime/Types/TypeHandler.h
index 0feb677..6034bf3 100644
--- a/lib/Runtime/Types/TypeHandler.h
+++ b/lib/Runtime/Types/TypeHandler.h
@@ -348,13 +348,17 @@
              (v) Seal
             (vi) Freeze
         */
-        bool GetIsLocked() const { return (this->flags & IsLockedFlag) != 0; }
+        bool GetIsLocked() const { return GetIsLocked(this->flags); }
+        static bool GetIsLocked(byte flags) { return (flags & IsLockedFlag) != 0; }
 
         bool GetIsShared() const { return (this->flags & IsSharedFlag) != 0; }
         bool GetMayBecomeShared() const { return (this->flags & MayBecomeSharedFlag) != 0; }
         bool GetIsOrMayBecomeShared() const { return (this->flags & (MayBecomeSharedFlag | IsSharedFlag)) != 0; }
         bool GetHasKnownSlot0() const { return (this->flags & HasKnownSlot0Flag) != 0; }
-        bool GetIsPrototype() const { return (this->flags & IsPrototypeFlag) != 0; }
+
+        bool GetIsPrototype() const { return GetIsPrototype(this->flags); }
+        static bool GetIsPrototype(byte flags) { return (flags & IsPrototypeFlag) != 0; }
+
         bool GetIsInlineSlotCapacityLocked() const { return (this->propertyTypes & PropertyTypesInlineSlotCapacityLocked) != 0; }
 
         void LockTypeHandler() { Assert(IsLockable()); SetFlags(IsLockedFlag); }
diff --git a/test/Bugs/misc_bugs.js b/test/Bugs/misc_bugs.js
index 9d11ecf..454914d 100644
--- a/test/Bugs/misc_bugs.js
+++ b/test/Bugs/misc_bugs.js
@@ -247,6 +247,18 @@
       }

   },

   {

+    name: "Init box javascript array : OS : 20517662",

+    body: function () {

+      var obj = {};

+      obj[0] = 11;

+      obj[1] = {};

+      obj[17] = 222;

+      obj[35] = 333; // This is will increase the size past the inline segment

+      

+      Object.assign({}, obj); // The InitBoxedInlineSegments will be called due to this call.

+    }

+  },

+  {

     name: "calling promise's function as constructor should not be allowed",

     body: function () {

         var var_0 = new Promise(function () {});                                           

@@ -258,6 +270,25 @@
         var_3 = Promise.prototype.finally.call(var_0, var_1);                              

         assert.throws(() => { new var_2([]).var_3(); },TypeError);

       }

+  },

+  {

+    name: "class name should not change if calling multiple times",

+    body: function () {

+        function getClass() {

+          class A {

+            constructor() {

+

+            }

+          };

+          return A;

+        }

+        let f1 = getClass();

+        let f2 = getClass();

+        let f3 = getClass();

+        assert.areEqual("A", f1.name);

+        assert.areEqual("A", f2.name);

+        assert.areEqual("A", f3.name);

+      }

   }

 

 ];

diff --git a/test/es6/bug_issue_5994.baseline b/test/es6/bug_issue_5994.baseline
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/es6/bug_issue_5994.baseline
diff --git a/test/es6/bug_issue_5994.js b/test/es6/bug_issue_5994.js
new file mode 100644
index 0000000..fb6a178
--- /dev/null
+++ b/test/es6/bug_issue_5994.js
@@ -0,0 +1,3 @@
+for (var var_01 = () => [].var_02[0][0](function (x, y) {}().var_03) in var_04) {

+    // \0asm\x01\0\0\0\x01À\x80\x80\x80\0\r`\x02\x7F\x7F\x01\x7F`\x02~~\x01\x7F`\x02}}\x01\x7F`\x02||\x01\x7F`\0\0`\0\x01\x7F`\0\x01~`\0\x01}`\0\x01|`\x02\x7F\x7F\0`\x02~~\0`\x02}}\0`\x02||\0\x03\x84\x81\x80\x80\0\x82\x01\0\0\x01\x01\x02\x02\x03\x03\x04\x04\x05\x05\x05\x05\x05\x05\x06\x06\x06\x05\x05\x07\x07\x07\x05\x05\b\b\b\x05\x05\t\n\x0B\f\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x04\x85\x80\x80\x80\0\x01p\x01\b\b\x05\x83\x80\x80\x80\0\x01\0\x01\x07ª\x88\x80\x80\0_\x07i32_add\0#\x07i32_sub\0$\x07i32_mul\0%\ti32_div_s\0&\ti32_div_u\0\'\ti32_rem_s\0(\ti32_rem_u\0)\x07i32_and\0*\x06i32_or\0+\x07i32_xor\0,\x07i32_shl\0-\ti32_shr_u\0.\ti32_shr_s\0/\x06i32_eq\x000\x06i32_ne\x001\bi32_lt_s\x002\bi32_le_s\x003\bi32_lt_u\x004\bi32_le_u\x005\bi32_gt_s\x006\bi32_ge_s\x007\bi32_gt_u\x008\bi32_ge_u\x009\ti32_store\0:\ni32_store8\0;\x0Bi32_store16\0<\bi32_call\0=\x11i32_call_indirect\0>\ni32_select\0?\x07i64_add\0@\x07i64_sub\0A\x07i64_mul\0B\ti64_div_s\0C\ti64_div_u\0D\ti64_rem_s\0E\ti64_rem_u\0F\x07i64_and\0G\x06i64_or\0H\x07i64_xor\0I\x07i64_shl\0J\ti64_shr_u\0K\ti64_shr_s\0L\x06i64_eq\0M\x06i64_ne\0N\bi64_lt_s\0O\bi64_le_s\0P\bi64_lt_u\0Q\bi64_le_u\0R\bi64_gt_s\0S\bi64_ge_s\0T\bi64_gt_u\0U\bi64_ge_u\0V\ti64_store\0W\ni64_store8\0X\x0Bi64_store16\0Y\x0Bi64_store32\0Z\bi64_call\0[\x11i64_call_indirect\0\\\ni64_select\0]\x07f32_add\0^\x07f32_sub\0_\x07f32_mul\0`\x07f32_div\0a\ff32_copysign\0b\x06f32_eq\0c\x06f32_ne\0d\x06f32_lt\0e\x06f32_le\0f\x06f32_gt\0g\x06f32_ge\0h\x07f32_min\0i\x07f32_max\0j\tf32_store\0k\bf32_call\0l\x11f32_call_indirect\0m\nf32_select\0n\x07f64_add\0o\x07f64_sub\0p\x07f64_mul\0q\x07f64_div\0r\ff64_copysign\0s\x06f64_eq\0t\x06f64_ne\0u\x06f64_lt\0v\x06f64_le\0w\x06f64_gt\0x\x06f64_ge\0y\x07f64_min\0z\x07f64_max\0{\tf64_store\0|\bf64_call\0}\x11f64_call_indirect\0~\nf64_select\0\x7F\x05br_if\0\x80\x01\bbr_table\0\x81\x01\t\x8E\x80\x80\x80\0\x01\0A\0\x0B\b\0\x01\x02\x03\x04\x05\x06\x07\n\xB2\x91\x80\x80\0\x82\x01\x84\x80\x80\x80\0\0A\x7F\x0B\x84\x80\x80\x80\0\0A~\x0B\x84\x80\x80\x80\0\0A\x7F\x0B\x84\x80\x80\x80\0\0A~\x0B\x84\x80\x80\x80\0\0A\x7F\x0B\x84\x80\x80\x80\0\0A~\x0B\x84\x80\x80\x80\0\0A\x7F\x0B\x84\x80\x80\x80\0\0A~\x0B\x89\x80\x80\x80\0\0A\bA\x006\x02\0\x0B\xA7\x80\x80\x80\0\0A\x0BA\n-\0\0:\0\0A\nA\t-\0\0:\0\0A\tA\b-\0\0:\0\0A\bA}:\0\0\x0B\x87\x80\x80\x80\0\0A\b(\x02\0\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x01:\0\0A\0\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x02:\0\0A\x01\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x03:\0\0A\x01\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x04:\0\0A\0\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x05:\0\0A\0\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x01:\0\0B\0\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x02:\0\0B\x01\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x03:\0\0B\x01\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x04:\0\0A\x02\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x05:\0\0A\0\x0B\x90\x80\x80\x80\0\0\x10\tA\bA\x01:\0\0C\0\0\0\0\x0B\x90\x80\x80\x80\0\0\x10\tA\bA\x02:\0\0C\0\0\x80?\x0B\x90\x80\x80\x80\0\0\x10\tA\bA\x03:\0\0C\0\0\x80?\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x04:\0\0A\x04\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x05:\0\0A\0\x0B\x94\x80\x80\x80\0\0\x10\tA\bA\x01:\0\0D\0\0\0\0\0\0\0\0\x0B\x94\x80\x80\x80\0\0\x10\tA\bA\x02:\0\0D\0\0\0\0\0\0ð?\x0B\x94\x80\x80\x80\0\0\x10\tA\bA\x03:\0\0D\0\0\0\0\0\0ð?\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x04:\0\0A\x06\x0B\x8D\x80\x80\x80\0\0\x10\tA\bA\x05:\0\0A\0\x0B\x82\x80\x80\x80\0\0\x0B\x82\x80\x80\x80\0\0\x0B\x82\x80\x80\x80\0\0\x0B\x82\x80\x80\x80\0\0\x0B\x8C\x80\x80\x80\0\0\x10\b\x10\x0B\x10\fj\x1A\x10\n\x0B\x8C\x80\x80\x80\0\0\x10\b\x10\x0B\x10\fk\x1A\x10\n\x0B\x8C\x80\x80\x80\0\0\x10\b\x10\x0B\x10\fl\x1A\x10\n\x0B\x8C\x80\x80\x80\0\0\x10\b\x10\x0B\x10\fm\x1A\x10\n\x01\0\0\0\x01À\x80\x80\x80\0\r`\x2

+}

diff --git a/test/es6/rlexe.xml b/test/es6/rlexe.xml
index 64fed61..207717a 100644
--- a/test/es6/rlexe.xml
+++ b/test/es6/rlexe.xml
@@ -1511,4 +1511,11 @@
     <compile-flags>-args summary -endargs</compile-flags>
   </default>
 </test>
+<test>
+  <default>
+    <files>bug_issue_5994.js</files>
+    <compile-flags>-MuteHostErrorMsg</compile-flags>
+    <baseline>bug_issue_5994.baseline</baseline>
+  </default>
+</test>
 </regress-exe>