@@ -1996,41 +1996,76 @@ BackwardPass::ProcessBailOutCopyProps(BailOutInfo * bailOutInfo, BVSparse<JitAre
19961996 NEXT_SLISTBASE_ENTRY_EDITING;
19971997}
19981998
1999- bool
2000- BackwardPass::ProcessBailOutInfo (IR::Instr * instr)
1999+
2000+ StackSym*
2001+ BackwardPass::ProcessByteCodeUsesDst (IR::ByteCodeUsesInstr * byteCodeUsesInstr)
20012002{
2002- if (this ->tag == Js::BackwardPhase)
2003+ Assert (this ->DoByteCodeUpwardExposedUsed ());
2004+ IR::Opnd * dst = byteCodeUsesInstr->GetDst ();
2005+ if (dst)
20032006 {
2004- // We don't need to fill in the bailout instruction in backward pass
2005- Assert (this ->func ->hasBailout || !instr->HasBailOutInfo ());
2006- Assert (!instr->HasBailOutInfo () || instr->GetBailOutInfo ()->byteCodeUpwardExposedUsed == nullptr || (this ->func ->HasTry () && this ->func ->DoOptimizeTry ()));
2007+ IR::RegOpnd * dstRegOpnd = dst->AsRegOpnd ();
2008+ StackSym * dstStackSym = dstRegOpnd->m_sym ->AsStackSym ();
2009+ Assert (!dstRegOpnd->GetIsJITOptimizedReg ());
2010+ Assert (dstStackSym->GetByteCodeRegSlot () != Js::Constants::NoRegister);
2011+ if (dstStackSym->GetType () != TyVar)
2012+ {
2013+ dstStackSym = dstStackSym->GetVarEquivSym (nullptr );
2014+ }
20072015
2008- if (instr->IsByteCodeUsesInstr ())
2016+ // If the current region is a Try, symbols in its write-through set shouldn't be cleared.
2017+ // Otherwise, symbols in the write-through set of the first try ancestor shouldn't be cleared.
2018+ if (!this ->currentRegion ||
2019+ !this ->CheckWriteThroughSymInRegion (this ->currentRegion , dstStackSym))
20092020 {
2010- // FGPeeps inserts bytecodeuses instrs with srcs. We need to look at them to set the proper
2011- // UpwardExposedUsed info and keep the defs alive.
2012- // The inliner inserts bytecodeuses instrs withs dsts, but we don't want to look at them for upwardExposedUsed
2013- // as it would cause real defs to look dead. We use these for bytecodeUpwardExposedUsed info only, which is needed
2014- // in the dead-store pass only.
2015- //
2016- // Handle the source side.
2017- IR::ByteCodeUsesInstr *byteCodeUsesInstr = instr->AsByteCodeUsesInstr ();
2018- const BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed = byteCodeUsesInstr->GetByteCodeUpwardExposedUsed ();
2019- if (byteCodeUpwardExposedUsed != nullptr )
2020- {
2021- this ->currentBlock ->upwardExposedUses ->Or (byteCodeUpwardExposedUsed);
2022- if (this ->DoByteCodeUpwardExposedUsed ())
2023- {
2024- this ->currentBlock ->byteCodeUpwardExposedUsed ->Or (byteCodeUpwardExposedUsed);
2025- }
2026- }
2027- return true ;
2021+ this ->currentBlock ->byteCodeUpwardExposedUsed ->Clear (dstStackSym->m_id );
2022+ return dstStackSym;
2023+
20282024 }
2025+ }
2026+ return nullptr ;
2027+ }
2028+
2029+ const BVSparse<JitArenaAllocator>*
2030+ BackwardPass::ProcessByteCodeUsesSrcs (IR::ByteCodeUsesInstr * byteCodeUsesInstr)
2031+ {
2032+ Assert (this ->DoByteCodeUpwardExposedUsed () || tag == Js::BackwardPhase);
2033+ const BVSparse<JitArenaAllocator>* byteCodeUpwardExposedUsed = byteCodeUsesInstr->GetByteCodeUpwardExposedUsed ();
2034+ if (byteCodeUpwardExposedUsed && this ->DoByteCodeUpwardExposedUsed ())
2035+ {
2036+ this ->currentBlock ->byteCodeUpwardExposedUsed ->Or (byteCodeUpwardExposedUsed);
2037+ }
2038+ return byteCodeUpwardExposedUsed;
2039+ }
2040+
2041+ bool
2042+ BackwardPass::ProcessByteCodeUsesInstr (IR::Instr * instr)
2043+ {
2044+ if (!instr->IsByteCodeUsesInstr ())
2045+ {
20292046 return false ;
20302047 }
20312048
2032- if (instr->IsByteCodeUsesInstr ())
2049+ IR::ByteCodeUsesInstr * byteCodeUsesInstr = instr->AsByteCodeUsesInstr ();
2050+
2051+ if (this ->tag == Js::BackwardPhase)
20332052 {
2053+ // FGPeeps inserts bytecodeuses instrs with srcs. We need to look at them to set the proper
2054+ // UpwardExposedUsed info and keep the defs alive.
2055+ // The inliner inserts bytecodeuses instrs withs dsts, but we don't want to look at them for upwardExposedUsed
2056+ // as it would cause real defs to look dead. We use these for bytecodeUpwardExposedUsed info only, which is needed
2057+ // in the dead-store pass only.
2058+ //
2059+ // Handle the source side.
2060+ const BVSparse<JitArenaAllocator>* byteCodeUpwardExposedUsed = ProcessByteCodeUsesSrcs (byteCodeUsesInstr);
2061+ if (byteCodeUpwardExposedUsed != nullptr )
2062+ {
2063+ this ->currentBlock ->upwardExposedUses ->Or (byteCodeUpwardExposedUsed);
2064+ }
2065+ }
2066+ else
2067+ {
2068+ Assert (tag == Js::DeadStorePhase);
20342069 Assert (instr->m_opcode == Js::OpCode::ByteCodeUses);
20352070#if DBG
20362071 if (this ->DoMarkTempObjectVerify () && (this ->currentBlock ->isDead || !this ->func ->hasBailout ))
@@ -2053,44 +2088,22 @@ BackwardPass::ProcessBailOutInfo(IR::Instr * instr)
20532088
20542089 if (this ->func ->hasBailout )
20552090 {
2056- Assert (this ->DoByteCodeUpwardExposedUsed ());
2057-
20582091 // Just collect the byte code uses, and remove the instruction
20592092 // We are going backward, process the dst first and then the src
2060- IR::Opnd * dst = instr->GetDst ();
2061- if (dst)
2062- {
2063- IR::RegOpnd * dstRegOpnd = dst->AsRegOpnd ();
2064- StackSym * dstStackSym = dstRegOpnd->m_sym ->AsStackSym ();
2065- Assert (!dstRegOpnd->GetIsJITOptimizedReg ());
2066- Assert (dstStackSym->GetByteCodeRegSlot () != Js::Constants::NoRegister);
2067- if (dstStackSym->GetType () != TyVar)
2068- {
2069- dstStackSym = dstStackSym->GetVarEquivSym (nullptr );
2070- }
2071-
2072- // If the current region is a Try, symbols in its write-through set shouldn't be cleared.
2073- // Otherwise, symbols in the write-through set of the first try ancestor shouldn't be cleared.
2074- if (!this ->currentRegion ||
2075- !this ->CheckWriteThroughSymInRegion (this ->currentRegion , dstStackSym))
2076- {
2077- this ->currentBlock ->byteCodeUpwardExposedUsed ->Clear (dstStackSym->m_id );
2093+ StackSym *dstStackSym = ProcessByteCodeUsesDst (byteCodeUsesInstr);
20782094#if DBG
2079- // We can only track first level function stack syms right now
2080- if (dstStackSym->GetByteCodeFunc () == this ->func )
2081- {
2082- this ->currentBlock ->byteCodeRestoreSyms [dstStackSym->GetByteCodeRegSlot ()] = nullptr ;
2083- }
2084- #endif
2085- }
2095+ // We can only track first level function stack syms right now
2096+ if (dstStackSym && dstStackSym->GetByteCodeFunc () == this ->func )
2097+ {
2098+ this ->currentBlock ->byteCodeRestoreSyms [dstStackSym->GetByteCodeRegSlot ()] = nullptr ;
20862099 }
2100+ #endif
20872101
2088- IR::ByteCodeUsesInstr *byteCodeUsesInstr = instr->AsByteCodeUsesInstr ();
2089- if (byteCodeUsesInstr->GetByteCodeUpwardExposedUsed () != nullptr )
2090- {
2091- this ->currentBlock ->byteCodeUpwardExposedUsed ->Or (byteCodeUsesInstr->GetByteCodeUpwardExposedUsed ());
2102+ const BVSparse<JitArenaAllocator>* byteCodeUpwardExposedUsed = ProcessByteCodeUsesSrcs (byteCodeUsesInstr);
20922103#if DBG
2093- FOREACH_BITSET_IN_SPARSEBV (symId, byteCodeUsesInstr->GetByteCodeUpwardExposedUsed ())
2104+ if (byteCodeUpwardExposedUsed)
2105+ {
2106+ FOREACH_BITSET_IN_SPARSEBV (symId, byteCodeUpwardExposedUsed)
20942107 {
20952108 StackSym * stackSym = this ->func ->m_symTable ->FindStackSym (symId);
20962109 Assert (!stackSym->IsTypeSpec ());
@@ -2108,16 +2121,14 @@ BackwardPass::ProcessBailOutInfo(IR::Instr * instr)
21082121 }
21092122 }
21102123 NEXT_BITSET_IN_SPARSEBV;
2111- #endif
21122124 }
2125+ #endif
21132126
2114- if (IsCollectionPass ())
2127+ if (IsCollectionPass ())
21152128 {
21162129 return true ;
21172130 }
21182131
2119- ProcessPendingPreOpBailOutInfo (instr);
2120-
21212132 PropertySym *propertySymUse = byteCodeUsesInstr->propertySymUse ;
21222133 if (propertySymUse && !this ->currentBlock ->isDead )
21232134 {
@@ -2133,13 +2144,27 @@ BackwardPass::ProcessBailOutInfo(IR::Instr * instr)
21332144 }
21342145
21352146 this ->currentBlock ->RemoveInstr (instr);
2136- return true ;
2147+ }
2148+ return true ;
2149+ }
2150+
2151+ bool
2152+ BackwardPass::ProcessBailOutInfo (IR::Instr * instr)
2153+ {
2154+ Assert (!instr->IsByteCodeUsesInstr ());
2155+ if (this ->tag == Js::BackwardPhase)
2156+ {
2157+ // We don't need to fill in the bailout instruction in backward pass
2158+ Assert (this ->func ->hasBailout || !instr->HasBailOutInfo ());
2159+ Assert (!instr->HasBailOutInfo () || instr->GetBailOutInfo ()->byteCodeUpwardExposedUsed == nullptr || (this ->func ->HasTry () && this ->func ->DoOptimizeTry ()));
2160+ return false ;
21372161 }
21382162
21392163 if (IsCollectionPass ())
21402164 {
21412165 return false ;
21422166 }
2167+ Assert (tag == Js::DeadStorePhase);
21432168
21442169 if (instr->HasBailOutInfo ())
21452170 {
@@ -2398,22 +2423,30 @@ BackwardPass::NeedBailOutOnImplicitCallsForTypedArrayStore(IR::Instr* instr)
23982423 return false ;
23992424}
24002425
2401- void
2426+ IR::Instr*
24022427BackwardPass::ProcessPendingPreOpBailOutInfo (IR::Instr *const currentInstr)
24032428{
24042429 Assert (!IsCollectionPass ());
24052430
24062431 if (!preOpBailOutInstrToProcess)
24072432 {
2408- return ;
2433+ return currentInstr-> m_prev ;
24092434 }
2435+ Assert (preOpBailOutInstrToProcess == currentInstr);
24102436
2411- IR::Instr *const prevInstr = currentInstr->m_prev ;
2412- if (prevInstr &&
2413- prevInstr->IsByteCodeUsesInstr () &&
2414- prevInstr->AsByteCodeUsesInstr ()->GetByteCodeOffset () == preOpBailOutInstrToProcess->GetByteCodeOffset ())
2437+ if (!this ->IsPrePass ())
24152438 {
2416- return ;
2439+ IR::Instr* prev = preOpBailOutInstrToProcess->m_prev ;
2440+ while (prev && preOpBailOutInstrToProcess->CanAggregateByteCodeUsesAcrossInstr (prev))
2441+ {
2442+ IR::Instr* instr = prev;
2443+ prev = prev->m_prev ;
2444+ if (instr->IsByteCodeUsesInstrFor (preOpBailOutInstrToProcess))
2445+ {
2446+ // If instr is a ByteCodeUsesInstr, it will remove it
2447+ ProcessByteCodeUsesInstr (instr);
2448+ }
2449+ }
24172450 }
24182451
24192452 // A pre-op bailout instruction was saved for bailout info processing after the instruction and relevant ByteCodeUses
@@ -2423,6 +2456,10 @@ BackwardPass::ProcessPendingPreOpBailOutInfo(IR::Instr *const currentInstr)
24232456 Assert (bailOutInfo->bailOutOffset == preOpBailOutInstrToProcess->GetByteCodeOffset ());
24242457 ProcessBailOutInfo (preOpBailOutInstrToProcess, bailOutInfo);
24252458 preOpBailOutInstrToProcess = nullptr ;
2459+
2460+ // We might have removed the prev instr if it was a ByteCodeUsesInstr
2461+ // Update the prevInstr on the main loop
2462+ return currentInstr->m_prev ;
24262463}
24272464
24282465void
@@ -2720,7 +2757,7 @@ BackwardPass::ProcessBlock(BasicBlock * block)
27202757 MarkScopeObjSymUseForStackArgOpt ();
27212758 ProcessBailOnStackArgsOutOfActualsRange ();
27222759
2723- if (ProcessNoImplicitCallUses (instr) || this ->ProcessBailOutInfo (instr))
2760+ if (ProcessNoImplicitCallUses (instr) || this ->ProcessByteCodeUsesInstr (instr) || this -> ProcessBailOutInfo (instr))
27242761 {
27252762 continue ;
27262763 }
@@ -3531,7 +3568,7 @@ BackwardPass::ProcessBlock(BasicBlock * block)
35313568 }
35323569 }
35333570#endif
3534- ProcessPendingPreOpBailOutInfo (instr);
3571+ instrPrev = ProcessPendingPreOpBailOutInfo (instr);
35353572
35363573#if DBG_DUMP
35373574 if (!IsCollectionPass () && IsTraceEnabled () && Js::Configuration::Global.flags .Verbose )
0 commit comments