[MERGE #6016 @pleath] ChakraCore Servicing Release for 1903

Merge pull request #6016 from pleath:servicing/1903

Addresses the following issue:

CVE-2019-0592
CVE-2019-0609
CVE-2019-0611
CVE-2019-0639
CVE-2019-0746
CVE-2019-0769
CVE-2019-0773
CVE-2019-0771
diff --git a/lib/Backend/BailOut.cpp b/lib/Backend/BailOut.cpp
index 2847584..84097ad 100644
--- a/lib/Backend/BailOut.cpp
+++ b/lib/Backend/BailOut.cpp
@@ -1403,6 +1403,7 @@
             //
             Js::Arguments generatorArgs = generator->GetArguments();
             Js::InterpreterStackFrame::Setup setup(function, generatorArgs, true, isInlinee);
+            Assert(setup.GetStackAllocationVarCount() == 0);
             size_t varAllocCount = setup.GetAllocationVarCount();
             size_t varSizeInBytes = varAllocCount * sizeof(Js::Var);
             DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
@@ -1415,11 +1416,14 @@
             // Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
             Js::Var invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Js::Var);
             memset(invalidVar, 0xFE, sizeof(Js::RecyclableObject));
-            newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, stackAddr, invalidVar);
-#else
-            newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, stackAddr);
 #endif
 
+            newInstance = setup.InitializeAllocation(allocation, nullptr, false, false, loopHeaderArray, stackAddr
+#if DBG
+                , invalidVar
+#endif
+                );
+
             newInstance->m_reader.Create(executeFunction);
 
             generator->SetFrame(newInstance, varSizeInBytes);
@@ -1429,18 +1433,28 @@
     {
         Js::InterpreterStackFrame::Setup setup(function, args, true, isInlinee);
         size_t varAllocCount = setup.GetAllocationVarCount();
-        size_t varSizeInBytes = varAllocCount * sizeof(Js::Var);
+        size_t stackVarAllocCount = setup.GetStackAllocationVarCount();
+        size_t varSizeInBytes;
+        Js::Var *stackAllocation = nullptr;
 
         // If the locals area exceeds a certain limit, allocate it from a private arena rather than
         // this frame. The current limit is based on an old assert on the number of locals we would allow here.
-        if (varAllocCount > Js::InterpreterStackFrame::LocalsThreshold)
+        if ((varAllocCount + stackVarAllocCount) > Js::InterpreterStackFrame::LocalsThreshold)
         {
             ArenaAllocator *tmpAlloc = nullptr;
             fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
+            varSizeInBytes = varAllocCount * sizeof(Js::Var);
             allocation = (Js::Var*)tmpAlloc->Alloc(varSizeInBytes);
+            if (stackVarAllocCount != 0)
+            {
+                size_t stackVarSizeInBytes = stackVarAllocCount * sizeof(Js::Var);
+                PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + stackVarSizeInBytes, returnAddress);
+                stackAllocation = (Js::Var*)_alloca(stackVarSizeInBytes);
+            }
         }
         else
         {
+            varSizeInBytes = (varAllocCount + stackVarAllocCount) * sizeof(Js::Var);
             PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes, returnAddress);
             allocation = (Js::Var*)_alloca(varSizeInBytes);
         }
@@ -1465,11 +1479,14 @@
 #if DBG
         Js::Var invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
         memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
-        newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, frameStackAddr, invalidStackVar);
-#else
-        newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, frameStackAddr);
 #endif
 
+        newInstance = setup.InitializeAllocation(allocation, stackAllocation, false, false, loopHeaderArray, frameStackAddr
+#if DBG
+            , invalidStackVar
+#endif
+            );
+
         newInstance->m_reader.Create(executeFunction);
     }
 
diff --git a/lib/Backend/EmitBuffer.cpp b/lib/Backend/EmitBuffer.cpp
index 2a4c407..107e942 100644
--- a/lib/Backend/EmitBuffer.cpp
+++ b/lib/Backend/EmitBuffer.cpp
@@ -414,7 +414,7 @@
 template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
 bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBufferForInterpreter(TEmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize)
 {
-    Assert(this->criticalSection.IsLocked());
+    AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
 
     Assert(allocation != nullptr);
     allocation->bytesUsed += bufferSize;
diff --git a/lib/Backend/FlowGraph.cpp b/lib/Backend/FlowGraph.cpp
index 5b56777..645b58e 100644
--- a/lib/Backend/FlowGraph.cpp
+++ b/lib/Backend/FlowGraph.cpp
@@ -5266,7 +5266,7 @@
             }
             if(symsRequiringCompensationToMergedValueInfoMap.Count() != 0)
             {
-                globOpt->InsertValueCompensation(pred, &symsRequiringCompensationToMergedValueInfoMap);
+                globOpt->InsertValueCompensation(pred, this, &symsRequiringCompensationToMergedValueInfoMap);
             }
         }
     } NEXT_PREDECESSOR_EDGE_EDITING;
diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp
index 1785d98..f09edda 100644
--- a/lib/Backend/GlobOpt.cpp
+++ b/lib/Backend/GlobOpt.cpp
@@ -601,7 +601,7 @@
 
                     if (block->loop->symsRequiringCompensationToMergedValueInfoMap)
                     {
-                        InsertValueCompensation(block, block->loop->symsRequiringCompensationToMergedValueInfoMap);
+                        InsertValueCompensation(block, succ, block->loop->symsRequiringCompensationToMergedValueInfoMap);
                     }
 
                     // Now that we're done with the liveFields within this loop, trim the set to those syms
@@ -1156,9 +1156,12 @@
 
 void GlobOpt::InsertValueCompensation(
     BasicBlock *const predecessor,
+    BasicBlock *const successor,
     const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap)
 {
     Assert(predecessor);
+    Assert(successor);
+    AssertOrFailFast(predecessor != successor);
     Assert(symsRequiringCompensationToMergedValueInfoMap->Count() != 0);
 
     IR::Instr *insertBeforeInstr = predecessor->GetLastInstr();
@@ -1182,7 +1185,7 @@
     }
 
     GlobOptBlockData &predecessorBlockData = predecessor->globOptData;
-    GlobOptBlockData &successorBlockData = *CurrentBlockData();
+    GlobOptBlockData &successorBlockData = successor->globOptData;
     struct DelayChangeValueInfo
     {
         Value* predecessorValue;
diff --git a/lib/Backend/GlobOpt.h b/lib/Backend/GlobOpt.h
index 8fddd80..b6afcf6 100644
--- a/lib/Backend/GlobOpt.h
+++ b/lib/Backend/GlobOpt.h
@@ -737,7 +737,7 @@
     void                    PreLowerCanonicalize(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val);
     void                    ProcessKills(IR::Instr *instr);
     void                    InsertCloneStrs(BasicBlock *toBlock, GlobOptBlockData *toData, GlobOptBlockData *fromData);
-    void                    InsertValueCompensation(BasicBlock *const predecessor, const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap);
+    void                    InsertValueCompensation(BasicBlock *const predecessor, BasicBlock *const successor, const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap);
     IR::Instr *             ToVarUses(IR::Instr *instr, IR::Opnd *opnd, bool isDst, Value *val);
     void                    ToVar(BVSparse<JitArenaAllocator> *bv, BasicBlock *block);
     IR::Instr *             ToVar(IR::Instr *instr, IR::RegOpnd *regOpnd, BasicBlock *block, Value *val, bool needsUpdate);
diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp
index 37fe1ff..6a8007d 100644
--- a/lib/Backend/GlobOptFields.cpp
+++ b/lib/Backend/GlobOptFields.cpp
@@ -450,9 +450,24 @@
                 break;
 
             case IR::JnHelperMethod::HelperRegExp_Exec:
+            case IR::JnHelperMethod::HelperRegExp_ExecResultNotUsed:
+            case IR::JnHelperMethod::HelperRegExp_ExecResultUsed:
+            case IR::JnHelperMethod::HelperRegExp_ExecResultUsedAndMayBeTemp:
+            case IR::JnHelperMethod::HelperRegExp_MatchResultNotUsed:
+            case IR::JnHelperMethod::HelperRegExp_MatchResultUsed:
+            case IR::JnHelperMethod::HelperRegExp_MatchResultUsedAndMayBeTemp:
+            case IR::JnHelperMethod::HelperRegExp_ReplaceStringResultUsed:
+            case IR::JnHelperMethod::HelperRegExp_ReplaceStringResultNotUsed:
+            case IR::JnHelperMethod::HelperRegExp_SplitResultNotUsed:
+            case IR::JnHelperMethod::HelperRegExp_SplitResultUsed:
+            case IR::JnHelperMethod::HelperRegExp_SplitResultUsedAndMayBeTemp:
+            case IR::JnHelperMethod::HelperRegExp_SymbolSearch:
             case IR::JnHelperMethod::HelperString_Match:
+            case IR::JnHelperMethod::HelperString_Search:
+            case IR::JnHelperMethod::HelperString_Split:
             case IR::JnHelperMethod::HelperString_Replace:
                 // Consider: We may not need to kill all fields here.
+                // We need to kill all the built-in properties that can be written, though, and there are a lot of those.
                 this->KillAllFields(bv);
                 break;
         }
diff --git a/lib/Backend/GlobOptIntBounds.cpp b/lib/Backend/GlobOptIntBounds.cpp
index 5136013..5821aed 100644
--- a/lib/Backend/GlobOptIntBounds.cpp
+++ b/lib/Backend/GlobOptIntBounds.cpp
@@ -2985,7 +2985,11 @@
     {
         // The loop count is constant, fold (indexOffset + loopCountMinusOne * maxMagnitudeChange)
         TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count is constant, folding\n"));
-        if(Int32Math::Mul(loopCount->LoopCountMinusOneConstantValue(), maxMagnitudeChange, &offset) ||
+
+        int loopCountMinusOnePlusOne = 0;
+
+        if (Int32Math::Add(loopCount->LoopCountMinusOneConstantValue(), 1, &loopCountMinusOnePlusOne) ||
+            Int32Math::Mul(loopCountMinusOnePlusOne, maxMagnitudeChange, &offset) ||
             Int32Math::Add(offset, indexOffset, &offset))
         {
             TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Folding failed\n"));
diff --git a/lib/Backend/IRBuilder.cpp b/lib/Backend/IRBuilder.cpp
index 75ee5c7..bef5404 100644
--- a/lib/Backend/IRBuilder.cpp
+++ b/lib/Backend/IRBuilder.cpp
@@ -1758,7 +1758,7 @@
         }
 
     case Js::OpCode::NewScObjectSimple:
-        dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
+        dstValueType = ValueType::GetObject(ObjectType::Object);
         // fall-through
     case Js::OpCode::LdFuncExpr:
         m_func->DisableCanDoInlineArgOpt();
@@ -5050,7 +5050,7 @@
             // lower take it from there...
             srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
             dstOpnd = this->BuildDstOpnd(dstRegSlot);
-            dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
+            dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Object));
             instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
 
             // Because we're going to be making decisions based off the value, we have to defer
diff --git a/lib/Backend/ServerScriptContext.cpp b/lib/Backend/ServerScriptContext.cpp
index ac270a2..b3ce241 100644
--- a/lib/Backend/ServerScriptContext.cpp
+++ b/lib/Backend/ServerScriptContext.cpp
@@ -312,6 +312,7 @@
 void
 ServerScriptContext::AddToDOMFastPathHelperMap(intptr_t funcInfoAddr, IR::JnHelperMethod helper)
 {
+    AutoCriticalSection cs(&m_cs);
     m_domFastPathHelperMap->Add(funcInfoAddr, helper);
 }
 
@@ -327,7 +328,7 @@
     GetEmitBufferManager(asmJsManager)->Decommit();
 }
 
-OOPEmitBufferManager *
+OOPEmitBufferManagerWithLock *
 ServerScriptContext::GetEmitBufferManager(bool asmJsManager)
 {
     if (asmJsManager)
@@ -343,11 +344,11 @@
 IR::JnHelperMethod
 ServerScriptContext::GetDOMFastPathHelper(intptr_t funcInfoAddr)
 {
+    AutoCriticalSection cs(&m_cs);
+
     IR::JnHelperMethod helper = IR::HelperInvalid;
 
-    m_domFastPathHelperMap->LockResize();
     m_domFastPathHelperMap->TryGetValue(funcInfoAddr, &helper);
-    m_domFastPathHelperMap->UnlockResize();
 
     return helper;
 }
@@ -392,6 +393,7 @@
 Field(Js::Var)*
 ServerScriptContext::GetModuleExportSlotArrayAddress(uint moduleIndex, uint slotIndex)
 {
+    AutoCriticalSection cs(&m_cs);
     AssertOrFailFast(m_moduleRecords.ContainsKey(moduleIndex));
     auto record = m_moduleRecords.Item(moduleIndex);
     return record->localExportSlotsAddr;
@@ -406,6 +408,7 @@
 void
 ServerScriptContext::AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr)
 {
+    AutoCriticalSection cs(&m_cs);
     Js::ServerSourceTextModuleRecord* record = HeapNewStructZ(Js::ServerSourceTextModuleRecord);
     record->moduleId = moduleId;
     record->localExportSlotsAddr = (Field(Js::Var)*)localExportSlotsAddr;
diff --git a/lib/Backend/ServerScriptContext.h b/lib/Backend/ServerScriptContext.h
index b20c406..4d32446 100644
--- a/lib/Backend/ServerScriptContext.h
+++ b/lib/Backend/ServerScriptContext.h
@@ -80,7 +80,7 @@
     void SetIsPRNGSeeded(bool value);
     void AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr);
     void UpdateGlobalObjectThisAddr(intptr_t globalThis);
-    OOPEmitBufferManager * GetEmitBufferManager(bool asmJsManager);
+    OOPEmitBufferManagerWithLock * GetEmitBufferManager(bool asmJsManager);
     void DecommitEmitBufferManager(bool asmJsManager);
 #ifdef PROFILE_EXEC
     Js::ScriptContextProfiler*  GetCodeGenProfiler(_In_ PageAllocator* pageAllocator);
@@ -100,10 +100,11 @@
     Js::ScriptContextProfiler * codeGenProfiler;
     CriticalSection profilerCS;
 #endif
+    CriticalSection m_cs;
     ArenaAllocator m_sourceCodeArena;
 
-    OOPEmitBufferManager m_interpreterThunkBufferManager;
-    OOPEmitBufferManager m_asmJsInterpreterThunkBufferManager;
+    OOPEmitBufferManagerWithLock m_interpreterThunkBufferManager;
+    OOPEmitBufferManagerWithLock m_asmJsInterpreterThunkBufferManager;
 
     ScriptContextDataIDL m_contextData;
     intptr_t m_globalThisAddr;
diff --git a/lib/JITIDL/ChakraJIT.acf b/lib/JITIDL/ChakraJIT.acf
index 9154454..88c2970 100644
--- a/lib/JITIDL/ChakraJIT.acf
+++ b/lib/JITIDL/ChakraJIT.acf
@@ -3,13 +3,26 @@
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
-typedef [context_handle_noserialize] PTHREADCONTEXT_HANDLE;
-typedef [context_handle_noserialize] PSCRIPTCONTEXT_HANDLE;
-
 [
     type_strict_context_handle
 ]
 interface IChakraJIT
 {
+    UpdatePropertyRecordMap([context_handle_noserialize] threadContextInfoAddress);
+    AddDOMFastPathHelper([context_handle_noserialize] scriptContextInfoAddress);
+    AddModuleRecordInfo([context_handle_noserialize] scriptContextInfoAddress);
+    SetWellKnownHostTypeId([context_handle_noserialize] threadContextInfoAddress);
+    CloseScriptContext([context_handle_noserialize] scriptContextInfoAddress);
+    FreeAllocation([context_handle_noserialize] scriptContextInfoAddress);
+    NewInterpreterThunkBlock([context_handle_noserialize] scriptContextInfoAddress);
+    DecommitInterpreterBufferManager([context_handle_noserialize] scriptContextInfoAddress);
+    IsNativeAddr([context_handle_noserialize] threadContextInfoAddress);
+    SetIsPRNGSeeded([context_handle_noserialize] scriptContextInfoAddress);
+    RemoteCodeGen([context_handle_noserialize] scriptContextInfoAddress);
+
+#if DBG
+    IsInterpreterThunkAddr([context_handle_noserialize] scriptContextInfoAddress);
+#endif
+
     typedef [encode, decode] pCodeGenWorkItemIDL;
 }
diff --git a/lib/JITServer/JITServer.cpp b/lib/JITServer/JITServer.cpp
index ef5568a..9602ba1 100644
--- a/lib/JITServer/JITServer.cpp
+++ b/lib/JITServer/JITServer.cpp
@@ -502,7 +502,7 @@
             ServerThreadContext * threadContext;
         } localAlloc(threadContext);
 
-        OOPEmitBufferManager * emitBufferManager = scriptContext->GetEmitBufferManager(thunkInput->asmJsThunk != FALSE);
+        OOPEmitBufferManagerWithLock * emitBufferManager = scriptContext->GetEmitBufferManager(thunkInput->asmJsThunk != FALSE);
 
         BYTE* runtimeAddress;
         EmitBufferAllocation<SectionAllocWrapper, PreReservedSectionAllocWrapper> * alloc = emitBufferManager->AllocateBuffer(InterpreterThunkEmitter::BlockSize, &runtimeAddress);
@@ -573,7 +573,7 @@
         *result = false;
         return RPC_S_INVALID_ARG;
     }
-    OOPEmitBufferManager * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
+    OOPEmitBufferManagerWithLock * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
     if (manager == nullptr)
     {
         *result = false;
diff --git a/lib/Runtime/Base/ScriptContext.cpp b/lib/Runtime/Base/ScriptContext.cpp
index c7242e5..4089663 100644
--- a/lib/Runtime/Base/ScriptContext.cpp
+++ b/lib/Runtime/Base/ScriptContext.cpp
@@ -1485,6 +1485,11 @@
         this->GetThreadContext()->RegisterScriptContext(this);
     }
 
+    bool ScriptContext::ExceedsStackNestedFuncCount(uint count)
+    {
+        return count >= (InterpreterStackFrame::LocalsThreshold / (sizeof(StackScriptFunction) / sizeof(Var)));
+    }
+
 #ifdef ENABLE_SCRIPT_DEBUGGING
     ArenaAllocator* ScriptContext::AllocatorForDiagnostics()
     {
diff --git a/lib/Runtime/Base/ScriptContext.h b/lib/Runtime/Base/ScriptContext.h
index f7d0015..06feff8 100644
--- a/lib/Runtime/Base/ScriptContext.h
+++ b/lib/Runtime/Base/ScriptContext.h
@@ -1089,6 +1089,8 @@
         ScriptConfiguration const * GetConfig(void) const { return &config; }
         CharClassifier const * GetCharClassifier(void) const;
 
+        static bool ExceedsStackNestedFuncCount(uint count);
+
         ThreadContext * GetThreadContext() const { return threadContext; }
 
         static const int MaxEvalSourceSize = 400;
diff --git a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp
index aa3b103..77c52fc 100644
--- a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp
+++ b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp
@@ -1839,7 +1839,8 @@
     Assert(!funcInfo->IsGlobalFunction());
     bool const doStackNestedFunc = !funcInfo->HasMaybeEscapedNestedFunc() && !IsInDebugMode()
         && !funcInfo->byteCodeFunction->IsCoroutine()
-        && !funcInfo->byteCodeFunction->IsModule();
+        && !funcInfo->byteCodeFunction->IsModule()
+        && !Js::ScriptContext::ExceedsStackNestedFuncCount(funcInfo->root->nestedCount);
     if (!doStackNestedFunc)
     {
         return false;
diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp
index 27f5277..8848ba7 100644
--- a/lib/Runtime/Language/InterpreterStackFrame.cpp
+++ b/lib/Runtime/Language/InterpreterStackFrame.cpp
@@ -1022,11 +1022,12 @@
         uint forInVarCount = bailedOut ? 0 : (this->executeFunction->GetForInLoopDepth() * (sizeof(Js::ForInObjectEnumerator) / sizeof(Var)));
         this->varAllocCount = k_stackFrameVarCount + localCount + this->executeFunction->GetOutParamMaxDepth() + forInVarCount +
             extraVarCount + this->executeFunction->GetInnerScopeCount();
+        this->stackVarAllocCount = 0;
 
         if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
         {
             // Track stack funcs...
-            this->varAllocCount += (sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount()) / sizeof(Var);
+            this->stackVarAllocCount += (sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount()) / sizeof(Var);
             if (!this->bailedOutOfInlinee)
             {
                 // Frame display (if environment depth is statically known)...
@@ -1034,21 +1035,22 @@
                 {
                     uint16 envDepth = this->executeFunction->GetEnvDepth();
                     Assert(envDepth != (uint16)-1);
-                    this->varAllocCount += sizeof(FrameDisplay) / sizeof(Var) + (envDepth + 1);
+                    this->stackVarAllocCount += sizeof(FrameDisplay) / sizeof(Var) + (envDepth + 1);
                 }
                 // ...and scope slots (if any)
                 if (this->executeFunction->DoStackScopeSlots())
                 {
                     uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
                     Assert(scopeSlots != 0);
-                    this->varAllocCount += scopeSlots + Js::ScopeSlots::FirstSlotIndex;
+                    this->stackVarAllocCount += scopeSlots + Js::ScopeSlots::FirstSlotIndex;
                 }
             }
         }
     }
 
     InterpreterStackFrame *
-    InterpreterStackFrame::Setup::InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, LoopHeader* loopHeaderArray, DWORD_PTR stackAddr
+    InterpreterStackFrame::Setup::InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, __in_ecount(stackVarAllocCount) Var * stackAllocation
+        , bool initParams, bool profileParams, LoopHeader* loopHeaderArray, DWORD_PTR stackAddr
 #if DBG
         , Var invalidStackVar
 #endif
@@ -1183,8 +1185,10 @@
 
         if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
         {
-            newInstance->InitializeStackFunctions((StackScriptFunction *)nextAllocBytes);
-            nextAllocBytes = nextAllocBytes + sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount();
+            char * stackAllocBytes = (stackAllocation != nullptr) ? (char*)stackAllocation : nextAllocBytes;
+
+            newInstance->InitializeStackFunctions((StackScriptFunction *)stackAllocBytes);
+            stackAllocBytes += sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount();
 
             if (!this->bailedOutOfInlinee)
             {
@@ -1192,20 +1196,24 @@
                 {
                     uint16 envDepth = this->executeFunction->GetEnvDepth();
                     Assert(envDepth != (uint16)-1);
-                    newInstance->localFrameDisplay = (FrameDisplay*)nextAllocBytes;
+                    newInstance->localFrameDisplay = (FrameDisplay*)stackAllocBytes;
                     newInstance->localFrameDisplay->SetLength(0); // Start with no scopes. It will get set in NewFrameDisplay
-                    nextAllocBytes += sizeof(FrameDisplay) + (envDepth + 1) * sizeof(Var);
+                    stackAllocBytes += sizeof(FrameDisplay) + (envDepth + 1) * sizeof(Var);
                 }
 
                 if (this->executeFunction->DoStackScopeSlots())
                 {
                     uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
                     Assert(scopeSlots != 0);
-                    ScopeSlots((Field(Var)*)nextAllocBytes).SetCount(0); // Start with count as 0. It will get set in NewScopeSlots
-                    newInstance->localClosure = nextAllocBytes;
-                    nextAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
+                    ScopeSlots((Field(Var)*)stackAllocBytes).SetCount(0); // Start with count as 0. It will get set in NewScopeSlots
+                    newInstance->localClosure = stackAllocBytes;
+                    stackAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
                 }
             }
+            if (stackAllocation == nullptr)
+            {
+                nextAllocBytes = stackAllocBytes;
+            }
         }
 #if ENABLE_PROFILE_INFO
         if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
@@ -1755,6 +1763,7 @@
         ScriptContext* functionScriptContext = function->GetScriptContext();
         Arguments generatorArgs = generator->GetArguments();
         InterpreterStackFrame::Setup setup(function, generatorArgs);
+        Assert(setup.GetStackAllocationVarCount() == 0);
         size_t varAllocCount = setup.GetAllocationVarCount();
         size_t varSizeInBytes = varAllocCount * sizeof(Var);
         DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // use any stack address from this frame to ensure correct debugging functionality
@@ -1768,11 +1777,14 @@
         Js::RecyclableObject* invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Var);
         AnalysisAssert(invalidVar);
         memset(reinterpret_cast<void*>(invalidVar), 0xFE, sizeof(Js::RecyclableObject));
-        newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr, invalidVar);
-#else
-        newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr);
 #endif
 
+        newInstance = setup.InitializeAllocation(allocation, nullptr, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr
+#if DBG
+            , invalidVar
+#endif
+            );
+
         newInstance->m_reader.Create(executeFunction);
 
         generator->SetFrame(newInstance, varSizeInBytes);
@@ -1914,7 +1926,8 @@
         {
             InterpreterStackFrame::Setup setup(function, args);
             size_t varAllocCount = setup.GetAllocationVarCount();
-            size_t varSizeInBytes = varAllocCount * sizeof(Var);
+            size_t stackVarAllocCount = setup.GetStackAllocationVarCount();
+            size_t varSizeInBytes;
 
             //
             // Allocate a new InterpreterStackFrame instance on the interpreter's virtual stack.
@@ -1922,18 +1935,27 @@
             DWORD_PTR stackAddr;
 
             Var* allocation;
+            Var* stackAllocation = nullptr;
 
             // If the locals area exceeds a certain limit, allocate it from a private arena rather than
             // this frame. The current limit is based on an old assert on the number of locals we would allow here.
-            if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
+            if ((varAllocCount + stackVarAllocCount) > InterpreterStackFrame::LocalsThreshold)
             {
                 ArenaAllocator *tmpAlloc = nullptr;
                 fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
+                varSizeInBytes = varAllocCount * sizeof(Var);
                 allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
                 stackAddr = reinterpret_cast<DWORD_PTR>(&allocation); // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
+                if (stackVarAllocCount != 0)
+                {
+                    size_t stackVarSizeInBytes = stackVarAllocCount * sizeof(Var);
+                    PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + stackVarSizeInBytes);
+                    stackAllocation = (Var*)_alloca(stackVarSizeInBytes);
+                }
             }
             else
             {
+                varSizeInBytes = (varAllocCount + stackVarAllocCount) * sizeof(Var);
                 PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes);
                 allocation = (Var*)_alloca(varSizeInBytes);
 #if DBG
@@ -1966,11 +1988,14 @@
 #if DBG
             Js::RecyclableObject * invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
             memset(reinterpret_cast<void*>(invalidStackVar), 0xFE, sizeof(Js::RecyclableObject));
-            newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr, invalidStackVar);
-#else
-            newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr);
 #endif
 
+            newInstance = setup.InitializeAllocation(allocation, stackAllocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr
+#if DBG
+                , invalidStackVar
+#endif
+                );
+
             newInstance->m_reader.Create(executeFunction);
         }
         //
@@ -2784,22 +2809,32 @@
         // after reparsing, we want to also use a new interpreter stack frame, as it will have different characteristics than the asm.js version
         InterpreterStackFrame::Setup setup(funcObj, m_inParams, m_inSlotsCount);
         size_t varAllocCount = setup.GetAllocationVarCount();
-        size_t varSizeInBytes = varAllocCount * sizeof(Var);
+        size_t stackVarAllocCount = setup.GetStackAllocationVarCount();
+        size_t varSizeInBytes;
 
         Var* allocation = nullptr;
+        Var* stackAllocation = nullptr;
         DWORD_PTR stackAddr;
         bool fReleaseAlloc = false;
-        if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
+        if ((varAllocCount + stackVarAllocCount) > InterpreterStackFrame::LocalsThreshold)
         {
             ArenaAllocator *tmpAlloc = nullptr;
             fReleaseAlloc = GetScriptContext()->EnsureInterpreterArena(&tmpAlloc);
+            varSizeInBytes = varAllocCount * sizeof(Var);
             allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
+            if (stackVarAllocCount != 0)
+            {
+                size_t stackVarSizeInBytes = stackVarAllocCount * sizeof(Var);
+                PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(GetScriptContext(), Js::Constants::MinStackInterpreter + stackVarSizeInBytes);
+                stackAllocation = (Var*)_alloca(stackVarSizeInBytes);
+            }
             // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
             // debugger stepping does not matter here, but it's worth being consistent with normal stack frame
             stackAddr = reinterpret_cast<DWORD_PTR>(&allocation);
         }
         else
         {
+            varSizeInBytes = (varAllocCount + stackVarAllocCount) * sizeof(Var);
             PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(GetScriptContext(), Js::Constants::MinStackInterpreter + varSizeInBytes);
             allocation = (Var*)_alloca(varSizeInBytes);
             stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
@@ -2808,10 +2843,14 @@
 #if DBG
         Var invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
         memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
-        InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr, invalidStackVar);
-#else
-        InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr);
 #endif
+
+        InterpreterStackFrame * newInstance = setup.InitializeAllocation(allocation, stackAllocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr
+#if DBG
+            , invalidStackVar
+#endif
+            );
+
         newInstance->m_reader.Create(funcObj->GetFunctionBody());
         // now that we have set up the new frame, let's interpret it!
         funcObj->GetFunctionBody()->BeginExecution();
diff --git a/lib/Runtime/Language/InterpreterStackFrame.h b/lib/Runtime/Language/InterpreterStackFrame.h
index 150672d..ae14024 100644
--- a/lib/Runtime/Language/InterpreterStackFrame.h
+++ b/lib/Runtime/Language/InterpreterStackFrame.h
@@ -50,14 +50,17 @@
             Setup(ScriptFunction * function, Arguments& args, bool bailout = false, bool inlinee = false);
             Setup(ScriptFunction * function, Var * inParams, int inSlotsCount);
             size_t GetAllocationVarCount() const { return varAllocCount; }
+            size_t GetStackAllocationVarCount() const { return stackVarAllocCount; }
 
             InterpreterStackFrame * AllocateAndInitialize(bool doProfile, bool * releaseAlloc);
 
+            InterpreterStackFrame * InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, __in_ecount(stackVarAllocCount) Var * stackAllocation
+                                                         , bool initParams, bool profileParams, LoopHeader* loopHeaderArray, DWORD_PTR stackAddr
 #if DBG
-            InterpreterStackFrame * InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, LoopHeader* loopHeaderArray, DWORD_PTR stackAddr, Var invalidStackVar);
-#else
-            InterpreterStackFrame * InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, LoopHeader* loopHeaderArray, DWORD_PTR stackAddr);
+                                                         , Var invalidStackVar
 #endif
+            );
+
             uint GetLocalCount() const { return localCount; }
 
         private:
@@ -75,6 +78,7 @@
             int inSlotsCount;
             uint localCount;
             uint varAllocCount;
+            uint stackVarAllocCount;
             uint inlineCacheCount;
             Js::CallFlags callFlags;
             bool bailedOut;
@@ -187,9 +191,6 @@
         // 16-byte aligned
         __declspec(align(16)) Var m_localSlots[0];           // Range of locals and temporaries
 
-        static const int LocalsThreshold = 32 * 1024; // Number of locals vars we'll allocate on the frame.
-                                                      // If there are more, we'll use an arena.
-
         //This class must have an empty ctor (otherwise it will break the code in InterpreterStackFrame::InterpreterThunk
         inline InterpreterStackFrame() { }
 
@@ -366,6 +367,9 @@
 
         void InitializeClosures();
 
+        static const int LocalsThreshold = 32 * 1024; // Number of locals vars we'll allocate on the frame.
+                                                      // If there are more, we'll use an arena.
+
     private:
 #if DYNAMIC_INTERPRETER_THUNK
         static JavascriptMethod EnsureDynamicInterpreterThunk(Js::ScriptFunction * function);
diff --git a/lib/Runtime/Library/EngineInterfaceObject.cpp b/lib/Runtime/Library/EngineInterfaceObject.cpp
index 221fd57..810904e 100644
--- a/lib/Runtime/Library/EngineInterfaceObject.cpp
+++ b/lib/Runtime/Library/EngineInterfaceObject.cpp
@@ -169,7 +169,7 @@
         // CommonNativeInterfaces is used as a prototype for the other native interface objects
         // to share the common APIs without requiring everyone to access EngineInterfaceObject.Common.
         this->commonNativeInterfaces = DynamicObject::New(recycler,
-            DynamicType::New(scriptContext, TypeIds_Object, library->GetObjectPrototype(), nullptr,
+            DynamicType::New(scriptContext, TypeIds_Object, library->GetNull(), nullptr,
             DeferredTypeHandler<InitializeCommonNativeInterfaces>::GetDefaultInstance()));
         library->AddMember(this, Js::PropertyIds::Common, this->commonNativeInterfaces);
 
diff --git a/lib/Runtime/Library/JavascriptLibrary.cpp b/lib/Runtime/Library/JavascriptLibrary.cpp
index c30e356..d7445f8 100644
--- a/lib/Runtime/Library/JavascriptLibrary.cpp
+++ b/lib/Runtime/Library/JavascriptLibrary.cpp
@@ -1363,7 +1363,7 @@
 
 #if defined(ENABLE_INTL_OBJECT) || defined(ENABLE_JS_BUILTINS) || defined(ENABLE_PROJECTION)
         engineInterfaceObject = EngineInterfaceObject::New(recycler,
-            DynamicType::New(scriptContext, TypeIds_EngineInterfaceObject, objectPrototype, nullptr,
+            DynamicType::New(scriptContext, TypeIds_EngineInterfaceObject, nullValue, nullptr,
             DeferredTypeHandler<InitializeEngineInterfaceObject>::GetDefaultInstance()));
 
 #ifdef ENABLE_INTL_OBJECT
@@ -1373,8 +1373,8 @@
 
 #ifdef ENABLE_JS_BUILTINS
         chakraLibraryObject = DynamicObject::New(recycler,
-            DynamicType::New(scriptContext, TypeIds_Object, objectPrototype, nullptr,
-                DeferredTypeHandler<InitializeChakraLibraryObject>::GetDefaultInstance()));
+            DynamicType::New(scriptContext, TypeIds_Object, nullValue, nullptr,
+            DeferredTypeHandler<InitializeChakraLibraryObject>::GetDefaultInstance()));
         if (CONFIG_FLAG(LdChakraLib)) {
             AddMember(globalObject, PropertyIds::__chakraLibrary, chakraLibraryObject);
         }
diff --git a/lib/Runtime/Library/JavascriptString.cpp b/lib/Runtime/Library/JavascriptString.cpp
index ec2ea3c..708db5d 100644
--- a/lib/Runtime/Library/JavascriptString.cpp
+++ b/lib/Runtime/Library/JavascriptString.cpp
@@ -3415,6 +3415,7 @@
 
     int JavascriptString::LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, charcount_t searchLen, charcount_t position)
     {
+        Assert(searchLen > 0);
         const char16 searchFirst = searchStr[0];
         uint32 lMatchedJump = searchLen;
         if (jmpTable[searchFirst].shift > 0)
@@ -3423,31 +3424,41 @@
         }
         WCHAR c;
         char16 const * p = inputStr + min(len - searchLen, position);
-        while(p >= inputStr)
+
+        while (true)
         {
+            uint32 remaining = (uint32)(p - inputStr);
+            uint32 backwardOffset = 0;
             // first character match, keep checking
             if (*p == searchFirst)
             {
-                if ( wmemcmp(p, searchStr, searchLen) == 0 )
+                if (wmemcmp(p, searchStr, searchLen) == 0)
                 {
-                    break;
+                    return (int)remaining;
                 }
-                p -= lMatchedJump;
+                backwardOffset = lMatchedJump;
             }
             else
             {
                 c = *p;
-                if ( 0 == ( c & ~0x7f ) && jmpTable[c].shift != 0 )
+                if (0 == (c & ~0x7f) && jmpTable[c].shift != 0)
                 {
-                    p -= jmpTable[c].shift;
+                    backwardOffset = jmpTable[c].shift;
                 }
                 else
                 {
-                    p -= searchLen;
+                    backwardOffset = searchLen;
                 }
             }
+            AssertOrFailFast(backwardOffset > 0);
+            if (backwardOffset > remaining)
+            {
+                break;
+            }
+            p -= backwardOffset;
         }
-        return ((p >= inputStr) ? (int)(p - inputStr) : -1);
+
+        return -1;
     }
 
     bool JavascriptString::BuildLastCharForwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen)
diff --git a/lib/Runtime/Library/StackScriptFunction.h b/lib/Runtime/Library/StackScriptFunction.h
index 0844e5f..8ed9339 100644
--- a/lib/Runtime/Library/StackScriptFunction.h
+++ b/lib/Runtime/Library/StackScriptFunction.h
@@ -85,11 +85,6 @@
 #if ENABLE_TTD
         virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
         virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
-
-        virtual void MarshalCrossSite_TTDInflate() override
-        {
-            Assert(false);
-        }
 #endif
 
     public:
diff --git a/lib/Runtime/Runtime.h b/lib/Runtime/Runtime.h
index 78de822..e5fe2a0 100644
--- a/lib/Runtime/Runtime.h
+++ b/lib/Runtime/Runtime.h
@@ -523,6 +523,7 @@
 //#include "Language/ModuleNamespace.h"
 #include "Types/ScriptFunctionType.h"
 #include "Library/ScriptFunction.h"
+#include "Library/StackScriptFunction.h"
 
 #include "Library/JavascriptProxy.h"
 
diff --git a/test/Optimizer/BoundCheckElimination.baseline b/test/Optimizer/BoundCheckElimination.baseline
index 011d76c..ef86a04 100644
--- a/test/Optimizer/BoundCheckElimination.baseline
+++ b/test/Optimizer/BoundCheckElimination.baseline
@@ -8,6 +8,7 @@
 Testtrace: BoundCheckHoist function testHoistability ( (#1.1), #2): Hoisting array upper bound check out of loop

 Testtrace: BoundCheckElimination function testHoistability ( (#1.1), #2): Eliminating array lower bound check

 Testtrace: BoundCheckElimination function testHoistability ( (#1.1), #2): Eliminating array upper bound check

+Testtrace: BoundCheckElimination function testHoistability ( (#1.1), #2): Separating array lower bound check

 Testtrace: BoundCheckHoist function testHoistability ( (#1.1), #2): Hoisting array upper bound check out of loop

 Testtrace: BoundCheckElimination function testHoistability ( (#1.1), #2): Eliminating array lower bound check

 Testtrace: BoundCheckElimination function testHoistability ( (#1.1), #2): Eliminating array upper bound check