[1.10>1.11] [MERGE #5827 @pleath] November, 2018 Servicing Update

Merge pull request #5827 from pleath:servicing/1811

Addresses the following:

CVE-2018-8541
CVE-2018-8542
CVE-2018-8543
CVE-2018-8551
CVE-2018-8555
CVE-2018-8556
CVE-2018-8557
CVE-2018-8588
diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp
index 6a1cc9d..3087b08 100644
--- a/lib/Backend/GlobOpt.cpp
+++ b/lib/Backend/GlobOpt.cpp
@@ -13375,6 +13375,7 @@
                     case IR::HelperArray_Shift:
                     case IR::HelperArray_Splice:
                     case IR::HelperArray_Unshift:
+                    case IR::HelperArray_Concat:
                         kills.SetKillsArrayHeadSegments();
                         kills.SetKillsArrayHeadSegmentLengths();
                         break;
@@ -13404,6 +13405,7 @@
                     //case IR::HelperArray_Sort:
                     case IR::HelperArray_Splice:
                     case IR::HelperArray_Unshift:
+                    case IR::HelperArray_Concat:
                         kills.SetKillsNativeArrays();
                         break;
                 }
diff --git a/lib/Backend/GlobOptBailOut.cpp b/lib/Backend/GlobOptBailOut.cpp
index 5a20d2b..c27a7af 100644
--- a/lib/Backend/GlobOptBailOut.cpp
+++ b/lib/Backend/GlobOptBailOut.cpp
@@ -1306,7 +1306,7 @@
         return
             !(
                 baseValueType.IsString() ||
-                (baseValueType.IsAnyArray() && baseValueType.GetObjectType() != ObjectType::ObjectWithArray) ||
+                baseValueType.IsArray() ||
                 (instr->HasBailOutInfo() && instr->GetBailOutKindNoBits() == IR::BailOutOnIrregularLength) // guarantees no implicit calls
             );
     }
diff --git a/lib/Backend/GlobOptExpr.cpp b/lib/Backend/GlobOptExpr.cpp
index 2af0dbd..cc1d4ff 100644
--- a/lib/Backend/GlobOptExpr.cpp
+++ b/lib/Backend/GlobOptExpr.cpp
@@ -844,6 +844,7 @@
             case IR::HelperArray_Shift:
             case IR::HelperArray_Unshift:
             case IR::HelperArray_Splice:
+            case IR::HelperArray_Concat:
                 this->currentBlock->globOptData.liveArrayValues->ClearAll();
                 break;
         }
diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp
index dba367c..85c7fb3 100644
--- a/lib/Backend/GlobOptFields.cpp
+++ b/lib/Backend/GlobOptFields.cpp
@@ -1900,20 +1900,8 @@
         switch (typeId)
         {
         default:
-            if (typeId > Js::TypeIds_LastStaticType)
-            {
-                Assert(typeId != Js::TypeIds_Proxy);
-                if (objValueType.IsLikelyArrayOrObjectWithArray())
-                {
-                    // If we have likely object with array before, we can't make it definite object with array
-                    // since we have only proved that it is an object.
-                    // Keep the likely array or object with array.
-                }
-                else
-                {
-                    newValueType = ValueType::GetObject(ObjectType::Object);
-                }
-            }
+            // Can't mark as definite object because it may actually be object-with-array.
+            // Consider: a value type that subsumes object, array, and object-with-array.
             break;
         case Js::TypeIds_NativeIntArray:
         case Js::TypeIds_NativeFloatArray:
diff --git a/lib/Backend/IRBuilder.cpp b/lib/Backend/IRBuilder.cpp
index 733d37f..f3edafe 100644
--- a/lib/Backend/IRBuilder.cpp
+++ b/lib/Backend/IRBuilder.cpp
@@ -3749,7 +3749,7 @@
 IR::Opnd*
 IRBuilder::GetEnvironmentOperand(uint32 offset)
 {
-    SymID symID;
+    StackSym* sym = nullptr;
     // The byte code doesn't refer directly to a closure environment. Get the implicit one
     // that's pointed to by the function body.
     if (m_func->DoStackFrameDisplay() && m_func->GetLocalFrameDisplaySym())
@@ -3760,19 +3760,35 @@
         this->AddInstr(
             IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func),
             offset);
-        symID = regOpnd->m_sym->m_id;
+        sym = regOpnd->m_sym;
     }
     else
     {
+        SymID symID;
         symID = this->GetEnvRegForInnerFrameDisplay();
         Assert(symID != Js::Constants::NoRegister);
         if (IsLoopBody() && !RegIsConstant(symID))
         {
             this->EnsureLoopBodyLoadSlot(symID);
         }
+
+        if (m_func->DoStackNestedFunc() && symID == GetEnvReg())
+        {
+            // Environment is not guaranteed constant during this function because it could become boxed during execution,
+            // so load the environment every time you need it.
+            IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func);
+            this->AddInstr(
+                IR::Instr::New(Js::OpCode::LdEnv, regOpnd, m_func),
+                offset);
+            sym = regOpnd->m_sym;
+        }
+        else
+        {
+            sym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func);
+        }
     }
 
-    return IR::RegOpnd::New(StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func), TyVar, m_func);
+    return IR::RegOpnd::New(sym, TyVar, m_func);
 }
 
 template <typename SizePolicy>
diff --git a/lib/Backend/Inline.cpp b/lib/Backend/Inline.cpp
index 695bf7b..b185ad8 100644
--- a/lib/Backend/Inline.cpp
+++ b/lib/Backend/Inline.cpp
@@ -5146,6 +5146,10 @@
                 else
                 {
                     instr->SetSrc1(funcObjOpnd);
+
+                    // This usage doesn't correspond with any byte code register, since interpreter stack frames
+                    // get their function reference via this->function rather than from a register.
+                    instr->GetSrc1()->SetIsJITOptimizedReg(true);
                 }
             }
             else
diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp
index 35247ae..cb3efbe 100644
--- a/lib/Backend/Lower.cpp
+++ b/lib/Backend/Lower.cpp
@@ -3765,13 +3765,11 @@
         GenerateMemInit(dstOpnd, Js::JavascriptNativeFloatArray::GetOffsetOfWeakFuncRef(), IR::AddrOpnd::New(weakFuncRef, IR::AddrOpndKindDynamicFunctionBodyWeakRef, m_func), instr, isZeroed);
         // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
         uint const offsetStart = sizeof(Js::SparseArraySegmentBase);
-        uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
-        i = i * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
-        for (; i < missingItemCount; i++)
+        for (; i < size; i++)
         {
             GenerateMemInit(
-                headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
-                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
+                headOpnd, offsetStart + i * sizeof(double),
+                GetMissingItemOpndForAssignment(TyFloat64, m_func),
                 instr, isZeroed);
         }
     }
@@ -3788,7 +3786,7 @@
         {
             GenerateMemInit(
                 headOpnd, offsetStart + i * sizeof(Js::Var),
-                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
+                GetMissingItemOpndForAssignment(TyVar, m_func),
                 instr, isZeroed);
         }
     }
@@ -4111,12 +4109,11 @@
 
         // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
         uint const offsetStart = sizeof(Js::SparseArraySegmentBase);
-        uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
-        for (uint i = 0; i < missingItemCount; i++)
+        for (uint i = 0; i < size; i++)
         {
             GenerateMemInit(
-                headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
-                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
+                headOpnd, offsetStart + i * sizeof(double),
+                GetMissingItemOpndForAssignment(TyFloat64, m_func),
                 instr, isZeroed);
         }
     }
@@ -4126,9 +4123,9 @@
         headOpnd = GenerateArrayObjectsAlloc<Js::JavascriptArray>(instr, &size, arrayInfo, &isZeroed, isNoArgs);
         for (uint i = 0; i < size; i++)
         {
-            GenerateMemInit(
+             GenerateMemInit(
                 headOpnd, offsetStart + i * sizeof(Js::Var),
-                IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true),
+                GetMissingItemOpndForAssignment(TyVar, m_func),
                 instr, isZeroed);
         }
     }
@@ -4159,8 +4156,8 @@
     uint allocationBucketsCount = ArrayType::AllocationBucketsCount;
     uint(*allocationBuckets)[Js::JavascriptArray::AllocationBucketsInfoSize];
     allocationBuckets = ArrayType::allocationBuckets;
-    uint sizeFactor = 1;
-    IRType missingItemType = (arrayInfo && arrayInfo->IsNativeIntArray()) ? IRType::TyInt32 : IRType::TyVar;
+    
+    IRType missingItemType = (arrayInfo ? arrayInfo->IsNativeIntArray() ? IRType::TyInt32 : arrayInfo->IsNativeFloatArray() ? IRType::TyFloat64 : IRType::TyVar : IRType::TyVar);
     IR::LabelInstr * arrayInitDone = IR::LabelInstr::New(Js::OpCode::Label, func);
 
     bool isNativeArray = arrayInfo && (arrayInfo->IsNativeIntArray() || arrayInfo->IsNativeFloatArray());
@@ -4172,9 +4169,7 @@
     }
     else if (arrayInfo && arrayInfo->IsNativeFloatArray())
     {
-        // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
-        sizeFactor = sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
-        sizeOfElement = sizeof(Js::JavascriptArray::MissingItem);
+        sizeOfElement = sizeof(double);
         GenerateArrayInfoIsNativeFloatAndNotIntArrayTest(instr, arrayInfo, arrayInfoAddr, helperLabel);
     }
     else
@@ -4204,7 +4199,7 @@
 
     for (uint8 i = 0;i < allocationBucketsCount;i++)
     {
-        missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor;
+        missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex];
 
         if (i > 0)
         {
@@ -4235,7 +4230,7 @@
     // Ensure no. of missingItems written are same
     Assert(missingItemIndex == missingItemInitializedSoFar);
     // Ensure no. of missingItems match what present in allocationBuckets
-    Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor);
+    Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex]);
 
     instr->InsertBefore(arrayInitDone);
 
@@ -4363,11 +4358,11 @@
 
     // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit.
     uint const offsetStart = sizeof(Js::SparseArraySegmentBase) + doubles->count * sizeof(double);
-    uint const missingItem = (size - doubles->count) * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem);
+    uint const missingItem = (size - doubles->count);
     for (uint i = 0; i < missingItem; i++)
     {
-        GenerateMemInit(headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem),
-            IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), instr, isHeadSegmentZeroed);
+        GenerateMemInit(headOpnd, offsetStart + i * sizeof(double),
+            GetMissingItemOpndForAssignment(TyFloat64, m_func), instr, isHeadSegmentZeroed);
     }
     // Skip pass the helper call
     IR::LabelInstr * doneLabel = IR::LabelInstr::New(Js::OpCode::Label, func);
diff --git a/lib/Parser/Scan.cpp b/lib/Parser/Scan.cpp
index 3aebff8..a1bb126 100644
--- a/lib/Parser/Scan.cpp
+++ b/lib/Parser/Scan.cpp
@@ -193,13 +193,16 @@
 // This is used to determine a length of BSTR, which can't contain a NUL character.
 //-----------------------------------------------------------------------------
 template <typename EncodingPolicy>
-charcount_t Scanner<EncodingPolicy>::LineLength(EncodedCharPtr first, EncodedCharPtr last)
+charcount_t Scanner<EncodingPolicy>::LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb)
 {
+    Assert(cb != nullptr);
+
     charcount_t result = 0;
     EncodedCharPtr p = first;
 
     for (;;)
     {
+        EncodedCharPtr prev = p;
         switch( this->template ReadFull<false>(p, last) )
         {
             case kchNWL: // _C_NWL
@@ -207,6 +210,13 @@
             case kchLS:
             case kchPS:
             case kchNUL: // _C_NUL
+                // p is now advanced past the line terminator character.
+                // We need to know the number of bytes making up the line, not including the line terminator character.
+                // To avoid subtracting a variable number of bytes because the line terminator characters are different
+                // number of bytes long (plus there may be multiple valid encodings for these characters) just keep
+                // track of the first byte of the line terminator character in prev.
+                Assert(prev >= first);
+                *cb = prev - first;
                 return result;
         }
         result++;
@@ -2313,10 +2323,11 @@
     typename EncodingPolicy::EncodedCharPtr pStart = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, ichMinLine);
 
     // Determine the length by scanning for the next newline
-    charcount_t cch = LineLength(pStart, m_pchLast);
+    size_t cb = 0;
+    charcount_t cch = LineLength(pStart, m_pchLast, &cb);
     Assert(cch <= LONG_MAX);
 
-    typename EncodingPolicy::EncodedCharPtr pEnd = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine + cch : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch);
+    typename EncodingPolicy::EncodedCharPtr pEnd = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine + cb : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch);
 
     *pbstrLine = SysAllocStringLen(NULL, cch);
     if (!*pbstrLine)
diff --git a/lib/Parser/Scan.h b/lib/Parser/Scan.h
index ae735f2..b34e163 100644
--- a/lib/Parser/Scan.h
+++ b/lib/Parser/Scan.h
@@ -780,7 +780,7 @@
 
     void ScanNewLine(uint ch);
     void NotifyScannedNewLine();
-    charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last);
+    charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb);
 
     tokens ScanIdentifier(bool identifyKwds, EncodedCharPtr *pp);
     BOOL FastIdentifierContinue(EncodedCharPtr&p, EncodedCharPtr last);
diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp
index bd0d8a6..27f5277 100644
--- a/lib/Runtime/Language/InterpreterStackFrame.cpp
+++ b/lib/Runtime/Language/InterpreterStackFrame.cpp
@@ -6727,6 +6727,12 @@
             // Finally exited with LeaveNull, We don't throw for early returns
             if (finallyEndOffset == 0 && exceptionObj)
             {
+#if ENABLE_NATIVE_CODEGEN
+                if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+                {
+                    JavascriptExceptionOperators::WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+                }
+#endif
                 JavascriptExceptionOperators::DoThrow(const_cast<Js::JavascriptExceptionObject *>(exceptionObj), scriptContext);
             }
             if (finallyEndOffset != 0)
diff --git a/lib/Runtime/Language/JavascriptExceptionOperators.cpp b/lib/Runtime/Language/JavascriptExceptionOperators.cpp
index e8d0923..2f64e7f 100644
--- a/lib/Runtime/Language/JavascriptExceptionOperators.cpp
+++ b/lib/Runtime/Language/JavascriptExceptionOperators.cpp
@@ -190,19 +190,23 @@
     {
         void                      *tryContinuation     = nullptr;
         JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)frame + hasBailedOutOffset));
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize);
-
-        try
         {
-            tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
+                tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
@@ -212,19 +216,9 @@
         if (exception)
         {
 #if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
             {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
-            }
-            else
-            {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                     WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, frame);
-                }
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
             }
 #endif
             bool hasBailedOut = *(bool*)((char*)frame + hasBailedOutOffset); // stack offsets are negative
@@ -251,21 +245,32 @@
         void                      *tryContinuation = nullptr;
         void                      *finallyContinuation = nullptr;
         JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize);
-        try
         {
-            tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
+                tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize);
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+#if ENABLE_NATIVE_CODEGEN
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+#endif
         }
 
         finallyContinuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize);
@@ -276,6 +281,12 @@
 
         if (exception)
         {
+#if ENABLE_NATIVE_CODEGEN
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
+#endif
             JavascriptExceptionOperators::DoThrow(exception, scriptContext);
         }
 
@@ -365,44 +376,40 @@
         int hasBailedOutOffset,
         ScriptContext *scriptContext)
     {
-        void                      *tryContinuation     = nullptr;
-        JavascriptExceptionObject *exception           = nullptr;
+        void                      *tryContinuation            = nullptr;
+        JavascriptExceptionObject *exception                  = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
+
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)localsPtr + hasBailedOutOffset));
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize);
-        try
         {
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
+            {
 #if defined(_M_ARM)
             tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #elif defined(_M_ARM64)
             tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
         if (exception)
         {
-#if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
-            {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
-            }
-            else
-            {
-                if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr);
-                }
-            }
-#endif
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+#if ENABLE_NATIVE_CODEGEN
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+#endif
             bool hasBailedOut = *(bool*)((char*)localsPtr + hasBailedOutOffset); // stack offsets are sp relative
             if (hasBailedOut)
             {
@@ -437,26 +444,38 @@
         void                      *tryContinuation = nullptr;
         void                      *finallyContinuation = nullptr;
         JavascriptExceptionObject *exception = nullptr;
+        void                      *tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize);
-
-        try
         {
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+
+            try
+            {
 #if defined(_M_ARM)
-            tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
+                tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #elif defined(_M_ARM64)
-            tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
+                tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize);
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                exception = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            exception = err.GetAndClear();
-        }
-
         if (exception)
         {
             // Clone static exception object early in case finally block overwrites it
             exception = exception->CloneIfStaticExceptionObject(scriptContext);
+
+#if ENABLE_NATIVE_CODEGEN
+            if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+#endif
         }
 
 #if defined(_M_ARM)
@@ -472,6 +491,12 @@
 
         if (exception)
         {
+#if ENABLE_NATIVE_CODEGEN
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
+#endif
             JavascriptExceptionOperators::DoThrow(exception, scriptContext);
         }
 
@@ -647,21 +672,24 @@
     {
         Js::JavascriptExceptionObject* pExceptionObject = NULL;
         void* continuationAddr = NULL;
+        void* tryHandlerAddrOfReturnAddr = nullptr;
 
         Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)framePtr + hasBailedOutOffset));
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout);
-
-        try
         {
-            // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
-            // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
-            // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
-            // In order to circumvent that we are throwing OutOfMemory.
-            if (!tryAddr)
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+            try
             {
-                Assert(false);
-                ThrowOutOfMemory(scriptContext);
-            }
+                // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
+                // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
+                // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
+                // In order to circumvent that we are throwing OutOfMemory.
+                if (!tryAddr)
+                {
+                    Assert(false);
+                    ThrowOutOfMemory(scriptContext);
+                }
 
 #ifdef _M_IX86
             void *savedEsp;
@@ -711,28 +739,19 @@
 #else
             AssertMsg(FALSE, "Unsupported native try-finally handler");
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                pExceptionObject = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch(const Js::JavascriptException& err)
-        {
-            pExceptionObject = err.GetAndClear();
-        }
-
         if (pExceptionObject)
         {
 #if ENABLE_NATIVE_CODEGEN
-            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
             {
-                if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
-                }
-            }
-            else
-            {
-                if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
-                {
-                    WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr);
-                }
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
             }
 #endif
             // Clone static exception object early in case finally block overwrites it
@@ -817,79 +836,91 @@
     {
         Js::JavascriptExceptionObject* pExceptionObject = NULL;
         void* continuationAddr = NULL;
+        void * tryHandlerAddrOfReturnAddr = nullptr;
 
         PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout);
-
-        try
         {
-            // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
-            // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
-            // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
-            // In order to circumvent that we are throwing OutOfMemory.
-            if (!tryAddr)
+            void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*));
+            Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr);
+
+            try
             {
-                Assert(false);
-                ThrowOutOfMemory(scriptContext);
-            }
+                // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function
+                // that may throw. The current workaround is to add the following dummy throw to prevent this optimization.
+                // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below).
+                // In order to circumvent that we are throwing OutOfMemory.
+                if (!tryAddr)
+                {
+                    Assert(false);
+                    ThrowOutOfMemory(scriptContext);
+                }
 
 #ifdef _M_IX86
-            void *savedEsp;
-            __asm
-            {
-                // Save and restore the callee-saved registers around the call.
-                // TODO: track register kills by region and generate per-region prologs and epilogs
-                push esi
-                push edi
-                push ebx
+                void *savedEsp;
+                __asm
+                {
+                    // Save and restore the callee-saved registers around the call.
+                    // TODO: track register kills by region and generate per-region prologs and epilogs
+                    push esi
+                    push edi
+                    push ebx
 
-                // 8-byte align frame to improve floating point perf of our JIT'd code.
-                // Save ESP
-                mov ecx, esp
-                mov savedEsp, ecx
-                and esp, -8
+                    // 8-byte align frame to improve floating point perf of our JIT'd code.
+                    // Save ESP
+                    mov ecx, esp
+                    mov savedEsp, ecx
+                    and esp, -8
 
-                // Set up the call target, save the current frame ptr, and adjust the frame to access
-                // locals in native code.
-                mov eax, tryAddr
+                    // Set up the call target, save the current frame ptr, and adjust the frame to access
+                    // locals in native code.
+                    mov eax, tryAddr
 
 #if 0 && defined(_CONTROL_FLOW_GUARD)
-                // verify that the call target is valid
-                mov  ebx, eax; save call target
-                mov  ecx, eax
-                call[__guard_check_icall_fptr]
-                mov  eax, ebx; restore call target
+                    // verify that the call target is valid
+                    mov  ebx, eax; save call target
+                    mov  ecx, eax
+                    call[__guard_check_icall_fptr]
+                    mov  eax, ebx; restore call target
 #endif
 
-                push ebp
-                mov ebp, framePtr
-                call eax
-                pop ebp
+                    push ebp
+                    mov ebp, framePtr
+                    call eax
+                    pop ebp
 
-                // The native code gives us the address where execution should continue on exit
-                // from the region.
-                mov continuationAddr, eax
+                    // The native code gives us the address where execution should continue on exit
+                    // from the region.
+                    mov continuationAddr, eax
 
-                // Restore ESP
-                mov ecx, savedEsp
-                mov esp, ecx
+                    // Restore ESP
+                    mov ecx, savedEsp
+                    mov esp, ecx
 
-                pop ebx
-                pop edi
-                pop esi
-            }
+                    pop ebx
+                    pop edi
+                    pop esi
+                }
 #else
-            AssertMsg(FALSE, "Unsupported native try-finally handler");
+                AssertMsg(FALSE, "Unsupported native try-finally handler");
 #endif
+            }
+            catch (const Js::JavascriptException& err)
+            {
+                pExceptionObject = err.GetAndClear();
+                tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr();
+            }
         }
-        catch (const Js::JavascriptException& err)
-        {
-            pExceptionObject = err.GetAndClear();
-        }
-
         if (pExceptionObject)
         {
             // Clone static exception object early in case finally block overwrites it
             pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext);
+
+#if ENABLE_NATIVE_CODEGEN
+            if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction())
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr);
+            }
+#endif
         }
 
         void* newContinuationAddr = NULL;
@@ -952,6 +983,12 @@
 
         if (pExceptionObject)
         {
+#if ENABLE_NATIVE_CODEGEN
+            if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr)
+            {
+                WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr());
+            }
+#endif
             JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext);
         }
 
diff --git a/lib/Runtime/Language/ValueType.cpp b/lib/Runtime/Language/ValueType.cpp
index 4e66e0b..fb264cb 100644
--- a/lib/Runtime/Language/ValueType.cpp
+++ b/lib/Runtime/Language/ValueType.cpp
@@ -1055,6 +1055,10 @@
         {
             // Any two different specific object types (excludes UninitializedObject and Object, which don't indicate any
             // specific type of object) merge to Object since the resulting type is not guaranteed to indicate any specific type
+            if (IsArrayOrObjectWithArray() || other.IsArrayOrObjectWithArray())
+            {
+                return Verify(GetObject(ObjectType::Object).ToLikely());
+            }
             merged.SetObjectType(ObjectType::Object);
             return Verify(merged);
         }
@@ -1945,13 +1949,18 @@
                 ));
 
             if(!(
-                    t0.IsObject() && t1.IsObject() &&                                                       // both are objects
+                    t0.IsObject() && t1.IsObject() &&                                                             // both are objects
                     (
-                        t0.GetObjectType() == ObjectType::UninitializedObject ||
-                        t1.GetObjectType() == ObjectType::UninitializedObject
-                    ) &&                                                                                    // one has an uninitialized object type
-                    (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object)    // one has a specific object type
-                ))                                                                                          // then the resulting object type is not guaranteed
+                        (
+                            (
+                                t0.GetObjectType() == ObjectType::UninitializedObject ||
+                                t1.GetObjectType() == ObjectType::UninitializedObject
+                            ) &&                                                                                  // one has an uninitialized object type
+                            (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object)  // one has a specific object type
+                        ) ||
+                        (t0.IsArrayOrObjectWithArray() || t1.IsArrayOrObjectWithArray()) // or one was an array or an object with array
+                    )
+                ))                                                                                                // then the resulting object type is not guaranteed
             {
                 Assert(m.IsNotInt() == (t0.IsNotInt() && t1.IsNotInt()));
             }
@@ -1990,13 +1999,18 @@
             Assert(m.IsLikelyString() == (t0.IsLikelyString() && t1.IsLikelyString()));
 
             if(!(
-                    t0.IsObject() && t1.IsObject() &&                                                       // both are objects
+                    t0.IsObject() && t1.IsObject() &&                                                             // both are objects
                     (
-                        t0.GetObjectType() == ObjectType::UninitializedObject ||
-                        t1.GetObjectType() == ObjectType::UninitializedObject
-                    ) &&                                                                                    // one has an uninitialized object type
-                    (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object)    // one has a specific object type
-                ))                                                                                          // then the resulting object type is not guaranteed
+                        (
+                            (
+                                t0.GetObjectType() == ObjectType::UninitializedObject ||
+                                t1.GetObjectType() == ObjectType::UninitializedObject
+                            ) &&                                                                                  // one has an uninitialized object type
+                            (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object)  // one has a specific object type
+                        ) ||
+                        (t0.IsArrayOrObjectWithArray() || t1.IsArrayOrObjectWithArray()) // or one was an array or an object with array
+                    )
+                ))                                                                                                // then the resulting object type is not guaranteed
             {
                 Assert(m.IsObject() == (t0.IsObject() && t1.IsObject()));
             }
diff --git a/lib/Runtime/Library/JavascriptArray.cpp b/lib/Runtime/Library/JavascriptArray.cpp
index ffed868..4947798 100644
--- a/lib/Runtime/Library/JavascriptArray.cpp
+++ b/lib/Runtime/Library/JavascriptArray.cpp
@@ -28,7 +28,7 @@
         { 8, 0, 0 },    // allocate space for 8 elements for array of length 6,7,8
     };
 
-    const Var JavascriptArray::MissingItem = (Var)FloatMissingItemPattern;
+    const Var JavascriptArray::MissingItem = (Var)VarMissingItemPattern;
 
 #if defined(TARGET_64)
     const Var JavascriptArray::IntMissingItemVar = (Var)(((uint64)IntMissingItemPattern << 32) | (uint32)IntMissingItemPattern);
@@ -2048,6 +2048,8 @@
                     {
                         ((SparseArraySegment<Var>*)seg)->elements[i] = JavascriptNumber::ToVar(ival, scriptContext);
                     }
+                    SparseArraySegment<Var>* newSeg = (SparseArraySegment<Var>*)seg;
+                    newSeg->FillSegmentBuffer(seg->length, seg->size);
                 }
                 prevSeg = seg;
             }
@@ -2243,7 +2245,7 @@
                     }
                 }
             }
-            if (seg == newSeg && shrinkFactor != 1)
+            if (seg == newSeg)
             {
                 // Fill the remaining slots.
                 newSeg->FillSegmentBuffer(i, seg->size);
diff --git a/lib/Runtime/Library/JavascriptArray.inl b/lib/Runtime/Library/JavascriptArray.inl
index 0f906e2..78de680 100644
--- a/lib/Runtime/Library/JavascriptArray.inl
+++ b/lib/Runtime/Library/JavascriptArray.inl
@@ -486,6 +486,8 @@
     template<typename T>
     inline void JavascriptArray::DirectSetItemInLastUsedSegmentAt(const uint32 offset, const T newValue)
     {
+        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
+
         SparseArraySegment<T> *const seg = (SparseArraySegment<T>*)GetLastUsedSegment();
         Assert(seg);
         Assert(offset < seg->size);
@@ -526,6 +528,8 @@
         const T newValue,
         StElemInfo *const stElemInfo)
     {
+        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
+
         SparseArraySegment<T> *const seg = SparseArraySegment<T>::From(head);
         Assert(seg);
         Assert(offset < seg->size);
@@ -1219,6 +1223,8 @@
     template<typename T>
     void JavascriptArray::DirectSetItem_Full(uint32 itemIndex, T newValue)
     {
+        Assert(!SparseArraySegment<T>::IsMissingItem(&newValue));
+
         DebugOnly(VerifyNotNeedMarshal(newValue));
         this->EnsureHead<T>();
         AnalysisAssert(head);
diff --git a/lib/Runtime/Library/SparseArraySegment.h b/lib/Runtime/Library/SparseArraySegment.h
index 219ad53..42edbc0 100644
--- a/lib/Runtime/Library/SparseArraySegment.h
+++ b/lib/Runtime/Library/SparseArraySegment.h
@@ -147,6 +147,7 @@
         return JavascriptArray::MissingItem;
     }
     template<> Var SparseArraySegment<int32>::GetMissingItemVar();
+    template<> Var SparseArraySegment<double>::GetMissingItemVar();
 
     template<>
     inline bool SparseArraySegment<double>::IsMissingItem(const double* value)
diff --git a/lib/Runtime/Library/SparseArraySegment.inl b/lib/Runtime/Library/SparseArraySegment.inl
index 669faea..8e0f151 100644
--- a/lib/Runtime/Library/SparseArraySegment.inl
+++ b/lib/Runtime/Library/SparseArraySegment.inl
@@ -229,6 +229,12 @@
         return JavascriptArray::IntMissingItemVar;
     }
 
+    template<>
+    inline Var SparseArraySegment<double>::GetMissingItemVar()
+    {
+        return (Var)FloatMissingItemPattern;
+    }
+
     template<typename T>
     void SparseArraySegment<T>::FillSegmentBuffer(uint32 start, uint32 size)
     {
diff --git a/lib/Runtime/RuntimeCommon.h b/lib/Runtime/RuntimeCommon.h
index 4849532..da1b7aa 100644
--- a/lib/Runtime/RuntimeCommon.h
+++ b/lib/Runtime/RuntimeCommon.h
@@ -179,6 +179,9 @@
 
 #if FLOATVAR
     const uint64 FloatTag_Value       = 0xFFFCull << 48;
+    const uint64 VarMissingItemPattern = 0x00040002FFF80002; // Float-tagged representation of FloatMissingItemPattern
+#else
+    const int32 VarMissingItemPattern = 0xFFF80002;
 #endif
     const uint64 FloatMissingItemPattern = 0xFFF80002FFF80002;
     const int32 IntMissingItemPattern = 0xFFF80002;
diff --git a/test/Bugs/bug_5585.js b/test/Bugs/bug_5585.js
new file mode 100644
index 0000000..afa523e
--- /dev/null
+++ b/test/Bugs/bug_5585.js
@@ -0,0 +1,55 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+
+let line = 't("摩"2)';
+let module_name = 'temp.js';
+WScript.RegisterModuleSource(module_name, line);
+
+var tests = [
+    {
+        name: "Syntax error thrown parsing dynamic module",
+        body: function () {
+            let source = `import(module_name)
+            .then(v => {
+                assert.fail("Parsing this module should not succeed");
+            }, e => {
+                assert.areEqual(line, e.source, "Source line causing compile error");
+            }).catch(e => {
+                console.log('fail: ' + e);
+                throw e;
+            });`
+
+            testRunner.LoadModule(source, 'samethread', true, false);
+        }
+    },
+    {
+        name: "Syntax error thrown parsing module code",
+        body: function () {
+            try {
+                WScript.LoadScriptFile(module_name, 'module');
+                assert.fail("Parsing this module should not succeed");
+            } catch(e) {
+                assert.areEqual(line, e.source, "Source line causing compile error");
+            }
+        }
+    },
+    {
+        name: "Error line which contains multi-byte UTF-8 sequence which is an end-of-line character",
+        body: function () {
+            WScript.RegisterModuleSource('temp2.js', 't("\u2028"2)');
+
+            try {
+                WScript.LoadScriptFile('temp2.js', 'module');
+                assert.fail("Parsing this module should not succeed");
+            } catch(e) {
+                assert.areEqual('t("', e.source, "Source line causing compile error");
+            }
+        }
+    }
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
diff --git a/test/Bugs/rlexe.xml b/test/Bugs/rlexe.xml
index 6f951bd..60e5d2e 100644
--- a/test/Bugs/rlexe.xml
+++ b/test/Bugs/rlexe.xml
@@ -530,4 +530,10 @@
       <tags>exclude_jshost</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>bug_5585.js</files>
+      <compile-flags>-esdynamicimport -mutehosterrormsg -args summary -endargs</compile-flags>
+    </default>
+  </test>
 </regress-exe>