@@ -865,12 +865,12 @@ BailOutRecord::RestoreValue(IR::BailOutKind bailOutKind, Js::JavascriptCallStack
865865 {
866866 // Register save space (offset is the register number and index into the register save space)
867867 // Index is one based, so subtract one
868- Js::Var * registerSaveSpace = registerSaves ? registerSaves : (Js::Var *)scriptContext-> GetThreadContext ()-> GetBailOutRegisterSaveSpace ( );
868+ AssertOrFailFast (registerSaves );
869869
870870 if (isFloat64)
871871 {
872872 Assert (RegTypes[LinearScanMD::GetRegisterFromSaveIndex (offset)] == TyFloat64);
873- dblValue = *((double *)&(registerSaveSpace [offset - 1 ]));
873+ dblValue = *((double *)&(registerSaves [offset - 1 ]));
874874#ifdef _M_ARM
875875 BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" Register %-4S %4d" ), RegNames[(offset - RegD0) / 2 + RegD0], offset);
876876#else
@@ -885,17 +885,17 @@ BailOutRecord::RestoreValue(IR::BailOutKind bailOutKind, Js::JavascriptCallStack
885885 isSimd128B8 || isSimd128B16
886886 )
887887 {
888- simdValue = *((SIMDValue *)&(registerSaveSpace [offset - 1 ]));
888+ simdValue = *((SIMDValue *)&(registerSaves [offset - 1 ]));
889889 }
890890 else if (isInt32)
891891 {
892892 Assert (RegTypes[LinearScanMD::GetRegisterFromSaveIndex (offset)] != TyFloat64);
893- int32Value = ::Math::PointerCastToIntegralTruncate<int32>(registerSaveSpace [offset - 1 ]);
893+ int32Value = ::Math::PointerCastToIntegralTruncate<int32>(registerSaves [offset - 1 ]);
894894 }
895895 else
896896 {
897897 Assert (RegTypes[LinearScanMD::GetRegisterFromSaveIndex (offset)] != TyFloat64);
898- value = registerSaveSpace [offset - 1 ];
898+ value = registerSaves [offset - 1 ];
899899 }
900900
901901 BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" Register %-4S %4d" ), RegNames[LinearScanMD::GetRegisterFromSaveIndex (offset)], offset);
@@ -1171,11 +1171,19 @@ uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Imp
11711171 // Do not remove the following code.
11721172 // Need to capture the int registers on stack as threadContext->bailOutRegisterSaveSpace is allocated from ThreadAlloc and is not scanned by recycler.
11731173 // We don't want to save float (xmm) registers as they can be huge and they cannot contain a var.
1174- Js::Var registerSaves[INT_REG_COUNT ];
1174+ // However, we're somewhat stuck. We need to keep the references around until we restore values, but
1175+ // we don't have a use for them. The easiest solution is to simply pass this into the corresponding
1176+ // parameter for BailOutcommonNoCodeGen, but that requires us to save all of the vars, not just the
1177+ // int ones. This is ultimately significantly more predictable than attempting to manage the lifetimes
1178+ // in some other way though. We can't just do what we were doing previously, which is saving values
1179+ // here and not passing them into BailOutCommonNoCodeGen, because then the compiler will likely get
1180+ // rid of the memcpy and then the dead registerSaves array, since it can figure out that there's no
1181+ // side effect (due to the GC not being something that the optimizer can, or should, reason about).
1182+ Js::Var registerSaves[BailOutRegisterSaveSlotCount];
11751183 js_memcpy_s (registerSaves, sizeof (registerSaves), (Js::Var *)layout->functionObject ->GetScriptContext ()->GetThreadContext ()->GetBailOutRegisterSaveSpace (),
11761184 sizeof (registerSaves));
11771185
1178- Js::Var result = BailOutCommonNoCodeGen (layout, bailOutRecord, bailOutOffset, returnAddress, bailOutKind, branchValue, nullptr , bailOutReturnValue, argoutRestoreAddress);
1186+ Js::Var result = BailOutCommonNoCodeGen (layout, bailOutRecord, bailOutOffset, returnAddress, bailOutKind, branchValue, registerSaves , bailOutReturnValue, argoutRestoreAddress);
11791187 ScheduleFunctionCodeGen (Js::ScriptFunction::FromVar (layout->functionObject ), nullptr , bailOutRecord, bailOutKind, bailOutOffset, savedImplicitCallFlags, returnAddress);
11801188 return result;
11811189}
@@ -1205,7 +1213,14 @@ uint32
12051213BailOutRecord::BailOutFromLoopBodyCommon (Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, uint32 bailOutOffset,
12061214 IR ::BailOutKind bailOutKind, Js::Var branchValue)
12071215{
1208- uint32 result = BailOutFromLoopBodyHelper (layout, bailOutRecord, bailOutOffset, bailOutKind, branchValue);
1216+ // This isn't strictly necessary if there's no allocations on this path, but because such an
1217+ // issue would be hard to notice and introduce some significant issues, we can do this copy.
1218+ // The problem from not doing this and then doing an allocation before RestoreValues is that
1219+ // the GC doesn't check the BailOutRegisterSaveSpace.
1220+ Js::Var registerSaves[BailOutRegisterSaveSlotCount];
1221+ js_memcpy_s (registerSaves, sizeof (registerSaves), (Js::Var *)layout->functionObject ->GetScriptContext ()->GetThreadContext ()->GetBailOutRegisterSaveSpace (),
1222+ sizeof (registerSaves));
1223+ uint32 result = BailOutFromLoopBodyHelper (layout, bailOutRecord, bailOutOffset, bailOutKind, branchValue, registerSaves);
12091224 ScheduleLoopBodyCodeGen (Js::ScriptFunction::FromVar (layout->functionObject ), nullptr , bailOutRecord, bailOutKind);
12101225 return result;
12111226}
0 commit comments